From 85d9617f90687330a69074fbcf8cc57d5548e88b Mon Sep 17 00:00:00 2001 From: 0xisk Date: Fri, 4 Apr 2025 09:53:50 +0200 Subject: [PATCH 001/282] test: adding more tests in ERC20 contract --- .../src/{erc20.compact => ERC20.compact} | 0 .../erc20/contract/src/test/erc20.test.ts | 75 ++++++++++++++++++- 2 files changed, 72 insertions(+), 3 deletions(-) rename contracts/erc20/contract/src/{erc20.compact => ERC20.compact} (100%) diff --git a/contracts/erc20/contract/src/erc20.compact b/contracts/erc20/contract/src/ERC20.compact similarity index 100% rename from contracts/erc20/contract/src/erc20.compact rename to contracts/erc20/contract/src/ERC20.compact diff --git a/contracts/erc20/contract/src/test/erc20.test.ts b/contracts/erc20/contract/src/test/erc20.test.ts index 86b018c2..a77ae72d 100644 --- a/contracts/erc20/contract/src/test/erc20.test.ts +++ b/contracts/erc20/contract/src/test/erc20.test.ts @@ -70,11 +70,11 @@ describe('ERC20', () => { }) describe('balanceOf', () => { - it('returns zero when requested account has no balance', () => { + it('should return zero when requested account has no balance', () => { expect(token.balanceOf(Z_OWNER)).toEqual(0n); }); - it('returns balance when requested account has tokens', () => { + it('should return balance when requested account has tokens', () => { token._mint(Z_OWNER, AMOUNT); expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); }); @@ -135,6 +135,22 @@ describe('ERC20', () => { token.transfer(utils.ZERO_ADDRESS, AMOUNT, caller); }).toThrow('ERC20: invalid receiver'); }); + + it('should allow transfer of 0 tokens', () => { + const txSuccess = token.transfer(Z_RECIPIENT, 0n, caller); + + expect(txSuccess).toBeTruthy(); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); + }); + + it('should handle transfer with empty _balances', () => { + caller = SPENDER; + + expect(() => { + token.transfer(Z_RECIPIENT, 1n, caller); + }).toThrow('ERC20: insufficient balance'); + }); }); describe('approve', () => { @@ -176,6 +192,30 @@ describe('ERC20', () => { token.approve(utils.ZERO_ADDRESS, AMOUNT, caller); }).toThrow('ERC20: invalid spender'); }); + + it('should transfer exact allowance and fail subsequent transfer', () => { + token._mint(Z_OWNER, AMOUNT); + caller = OWNER; + token.approve(Z_SPENDER, AMOUNT, caller); + + caller = SPENDER; + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, 1n, caller); + }).toThrow('ERC20: insufficient allowance'); + }); + + it('should allow approve of 0 tokens', () => { + caller = OWNER; + token.approve(Z_SPENDER, 0n, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + + it('should handle allowance with empty _allowances', () => { + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); }); describe('transferFrom', () => { @@ -291,7 +331,7 @@ describe('ERC20', () => { expect(token.balanceOf(Z_OWNER)).toEqual(1n); expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); - }) + }); }) describe('_mint', () => { @@ -314,6 +354,12 @@ describe('ERC20', () => { token._mint(utils.ZERO_ADDRESS, AMOUNT); }).toThrow('ERC20: invalid receiver'); }); + + it('should allow mint of 0 tokens', () => { + token._mint(Z_OWNER, 0n); + expect(token.totalSupply()).toEqual(0n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); }); describe('_burn', () => { @@ -340,6 +386,12 @@ describe('ERC20', () => { token._burn(Z_OWNER, AMOUNT + 1n); }).toThrow('ERC20: insufficient balance'); }); + + it('should allow burn of 0 tokens', () => { + token._burn(Z_OWNER, 0n); + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + }); }); describe('_update', () => { @@ -389,4 +441,21 @@ describe('ERC20', () => { expect(token.isZero(SOME_CONTRACT)).toBeFalsy; }); }); + + describe('Multiple Operations', () => { + it('should handle mint → transfer → burn sequence', () => { + token._mint(Z_OWNER, AMOUNT); + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + + caller = OWNER; + token.transfer(Z_RECIPIENT, AMOUNT - 1n, caller); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); + + token._burn(Z_OWNER, 1n); + expect(token.totalSupply()).toEqual(AMOUNT - 1n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + }); }); From 49e5ef2c4e61eaa2b5e50b14c6b8d9f0d1154490 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Mon, 7 Apr 2025 13:34:53 -0400 Subject: [PATCH 002/282] WIP --- contracts/erc721/contract/.eslintignore | 1 + contracts/erc721/contract/.eslintrc.cjs | 30 ++ contracts/erc721/contract/jest.config.ts | 28 ++ contracts/erc721/contract/js-resolver.cjs | 16 + contracts/erc721/contract/package.json | 29 ++ contracts/erc721/contract/src/erc721.compact | 33 +++ contracts/erc721/contract/src/index.ts | 2 + .../erc721/contract/src/test/erc721-setup.ts | 108 +++++++ .../erc721/contract/src/test/erc721.test.ts | 279 ++++++++++++++++++ contracts/erc721/contract/src/test/types.ts | 4 + contracts/erc721/contract/src/test/utils.ts | 78 +++++ contracts/erc721/contract/src/witnesses.ts | 7 + contracts/erc721/contract/tsconfig.build.json | 5 + contracts/erc721/contract/tsconfig.json | 21 ++ package.json | 3 +- yarn.lock | 11 + 16 files changed, 654 insertions(+), 1 deletion(-) create mode 100644 contracts/erc721/contract/.eslintignore create mode 100644 contracts/erc721/contract/.eslintrc.cjs create mode 100644 contracts/erc721/contract/jest.config.ts create mode 100644 contracts/erc721/contract/js-resolver.cjs create mode 100644 contracts/erc721/contract/package.json create mode 100644 contracts/erc721/contract/src/erc721.compact create mode 100644 contracts/erc721/contract/src/index.ts create mode 100644 contracts/erc721/contract/src/test/erc721-setup.ts create mode 100644 contracts/erc721/contract/src/test/erc721.test.ts create mode 100644 contracts/erc721/contract/src/test/types.ts create mode 100644 contracts/erc721/contract/src/test/utils.ts create mode 100644 contracts/erc721/contract/src/witnesses.ts create mode 100644 contracts/erc721/contract/tsconfig.build.json create mode 100644 contracts/erc721/contract/tsconfig.json diff --git a/contracts/erc721/contract/.eslintignore b/contracts/erc721/contract/.eslintignore new file mode 100644 index 00000000..652df825 --- /dev/null +++ b/contracts/erc721/contract/.eslintignore @@ -0,0 +1 @@ +src/managed diff --git a/contracts/erc721/contract/.eslintrc.cjs b/contracts/erc721/contract/.eslintrc.cjs new file mode 100644 index 00000000..581f1d49 --- /dev/null +++ b/contracts/erc721/contract/.eslintrc.cjs @@ -0,0 +1,30 @@ +module.exports = { + env: { + browser: true, + es2021: true, + node: true, + jest: true, + }, + extends: [ + 'standard-with-typescript', + 'plugin:prettier/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + ], + overrides: [], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['tsconfig.json'], + }, + rules: { + '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 + '@typescript-eslint/no-floating-promises': 'warn', + '@typescript-eslint/promise-function-async': 'off', + '@typescript-eslint/no-redeclare': 'off', + '@typescript-eslint/no-invalid-void-type': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/consistent-type-definitions': 'off' + }, +}; diff --git a/contracts/erc721/contract/jest.config.ts b/contracts/erc721/contract/jest.config.ts new file mode 100644 index 00000000..edbdaeba --- /dev/null +++ b/contracts/erc721/contract/jest.config.ts @@ -0,0 +1,28 @@ +import type { Config } from "@jest/types"; + +const config: Config.InitialOptions = { + preset: "ts-jest/presets/default-esm", + testEnvironment: "node", + verbose: true, + roots: [""], + modulePaths: [""], + passWithNoTests: false, + testMatch: ["**/*.test.ts"], + extensionsToTreatAsEsm: [".ts"], + collectCoverage: true, + resolver: '/js-resolver.cjs', + coverageThreshold: { + global: { + //branches: 60, + //functions: 75, + //lines: 70, + }, + }, + reporters: [ + "default", + ["jest-junit", { outputDirectory: "reports", outputName: "report.xml" }], + ["jest-html-reporters", { publicPath: "reports", filename: "report.html" }], + ], +}; + +export default config; diff --git a/contracts/erc721/contract/js-resolver.cjs b/contracts/erc721/contract/js-resolver.cjs new file mode 100644 index 00000000..cc9ed285 --- /dev/null +++ b/contracts/erc721/contract/js-resolver.cjs @@ -0,0 +1,16 @@ +const jsResolver = (path, options) => { + const jsExtRegex = /\.js$/i + const resolver = options.defaultResolver + if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { + const newPath = path.replace(jsExtRegex, '.ts'); + try { + return resolver(newPath, options) + } catch { + // use default resolver + } + } + + return resolver(path, options) +} + +module.exports = jsResolver diff --git a/contracts/erc721/contract/package.json b/contracts/erc721/contract/package.json new file mode 100644 index 00000000..01eeea4e --- /dev/null +++ b/contracts/erc721/contract/package.json @@ -0,0 +1,29 @@ +{ + "name": "@openzeppelin-midnight-contracts/erc721-contract", + "type": "module", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "scripts": { + "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", + "test": "NODE_OPTIONS=--experimental-vm-modules jest", + "prepack": "yarn build", + "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/erc721.compact ./dist", + "lint": "eslint src", + "typecheck": "tsc -p tsconfig.json --noEmit" + }, + "devDependencies": { + "@midnight-ntwrk/compact": "workspace:*", + "eslint": "^8.52.0", + "jest": "^29.7.0", + "typescript": "^5.2.2" + } +} diff --git a/contracts/erc721/contract/src/erc721.compact b/contracts/erc721/contract/src/erc721.compact new file mode 100644 index 00000000..f14c79d2 --- /dev/null +++ b/contracts/erc721/contract/src/erc721.compact @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.14.0; + +import CompactStandardLibrary; + +export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; + +/// Public state +export sealed ledger name: Maybe>; +export sealed ledger symbol: Maybe>; +export ledger owners: Map, Either>; +export ledger balances: Map, Uint<256>>; +export ledger tokenApprovals: Map, Either>; +export ledger operatorApprovals: Map, Map, >; + +/** + * @description Initializes the contract. + * @dev Move logic to initializer to set this as a base contract. + * + * @param _name - The name of the token. + * @param _symbol - The symbol of the token. + * @param _decimals - The number of decimals used to get the user representation. + */ +constructor( + _name: Maybe>, + _symbol: Maybe>, +) { + name = _name; + symbol = _symbol; +} + + diff --git a/contracts/erc721/contract/src/index.ts b/contracts/erc721/contract/src/index.ts new file mode 100644 index 00000000..b2fe5df9 --- /dev/null +++ b/contracts/erc721/contract/src/index.ts @@ -0,0 +1,2 @@ +export * from './artifacts/erc721/contract/index.cjs'; +export * from './witnesses.js'; diff --git a/contracts/erc721/contract/src/test/erc721-setup.ts b/contracts/erc721/contract/src/test/erc721-setup.ts new file mode 100644 index 00000000..6b1be532 --- /dev/null +++ b/contracts/erc721/contract/src/test/erc721-setup.ts @@ -0,0 +1,108 @@ +import { type CircuitContext, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; +import { Contract, type Ledger, ledger, ZswapCoinPublicKey, ContractAddress, Either } from '../artifacts/erc20/contract/index.cjs'; +import { type ERC20PrivateState, witnesses } from '../witnesses.js'; +import { MaybeString } from './types.js'; + +export class ERC20Mock { + readonly contract: Contract; + readonly contractAddress: string; + circuitContext: CircuitContext; + + constructor(name: MaybeString, symbol: MaybeString, decimals: bigint) { + this.contract = new Contract(witnesses); + const { currentPrivateState, currentContractState, currentZswapLocalState } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)), name, symbol, decimals + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext(currentContractState.data, sampleContractAddress()), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + public getLedger(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + public getPrivateState(): ERC20PrivateState { + return this.circuitContext.currentPrivateState; + } + + public balanceOf(account: Either): bigint { + return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; + } + + public allowance( + owner: Either, + spender: Either + ): bigint { + return this.contract.impureCircuits.allowance(this.circuitContext, owner, spender).result; + } + + public transfer(to: Either, value: bigint): boolean { + return this.contract.impureCircuits.transfer(this.circuitContext, to, value).result; + } + + public transferFrom( + from: Either, + to: Either, + value: bigint + ): boolean { + return this.contract.impureCircuits.transferFrom(this.circuitContext, from, to, value).result; + } + + public approve(spender: Either, value: bigint): boolean { + return this.contract.impureCircuits.approve(this.circuitContext, spender, value).result; + } + + public _approve( + owner: Either, + spender: Either, + value: bigint + ) { + this.circuitContext = this.contract.impureCircuits._approve(this.circuitContext, owner, spender, value).context; + return ledger(this.circuitContext.transactionContext.state); + } + + public _transfer( + from: Either, + to: Either, + value: bigint + ) { + this.circuitContext = this.contract.impureCircuits._transfer(this.circuitContext, from, to, value).context; + return ledger(this.circuitContext.transactionContext.state); + } + + public _mint(account: Either, value: bigint) { + this.circuitContext = this.contract.impureCircuits._mint(this.circuitContext, account, value).context; + return ledger(this.circuitContext.transactionContext.state); + } + + public _burn(account: Either, value: bigint) { + this.circuitContext = this.contract.impureCircuits._burn(this.circuitContext, account, value).context; + return ledger(this.circuitContext.transactionContext.state); + } + public _update( + from: Either, + to: Either, + value: bigint + ) { + this.circuitContext = this.contract.impureCircuits._update(this.circuitContext, from, to, value).context; + return ledger(this.circuitContext.transactionContext.state); + } + + public _spendAllowance( + owner: Either, + spender: Either, + value: bigint + ) { + this.circuitContext = this.contract.impureCircuits._spendAllowance(this.circuitContext, owner, spender, value).context; + return ledger(this.circuitContext.transactionContext.state); + } + + public _isZero(address: Either): boolean { + return this.contract.circuits._isZero(this.circuitContext, address).result; + } +} diff --git a/contracts/erc721/contract/src/test/erc721.test.ts b/contracts/erc721/contract/src/test/erc721.test.ts new file mode 100644 index 00000000..e1274631 --- /dev/null +++ b/contracts/erc721/contract/src/test/erc721.test.ts @@ -0,0 +1,279 @@ +import { it, describe, expect } from '@jest/globals'; +import { ERC20Mock } from './erc721-setup.js'; +import { NetworkId, setNetworkId } from '@midnight-ntwrk/midnight-js-network-id'; +import { MaybeString } from './types.js'; +import * as utils from './utils.js'; + +// +// Test vals +// + +const NO_STRING: MaybeString = { + is_some: false, + value: '' +}; +const NAME: MaybeString = { + is_some: true, + value: "NAME" +}; +const SYMBOL: MaybeString = { + is_some: true, + value: "SYMBOL" +}; +const DECIMALS: bigint = 18n; + +const AMOUNT: bigint = BigInt(250); +const MAX_UINT64 = BigInt(2 ** 64) - BigInt(1); +const MAX_UINT256 = BigInt(2 ** 256) - BigInt(1); + +const OWNER = utils.createEitherTestUser('OWNER'); +const RECIPIENT = utils.createEitherTestUser('RECIPIENT'); +const SPENDER = utils.createEitherTestUser('SPENDER'); +const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); + +// +// Test +// + +setNetworkId(NetworkId.Undeployed); +let token: any; + +describe('ERC20', () => { + beforeEach(() => { + token = new ERC20Mock(NAME, SYMBOL, DECIMALS); + }); + + describe('initialize', () => { + it('initializes the correct state', () => { + const state = token.getLedger(); + + expect(state.totalSupply).toEqual(0n); + expect(state.name).toEqual(NAME); + expect(state.symbol).toEqual(SYMBOL); + expect(state.decimals).toEqual(DECIMALS); + }); + + it('initializes no metadata state', () => { + const noDecimals: bigint = 0n; + + const token = new ERC20Mock(NO_STRING, NO_STRING, noDecimals); + const state = token.getLedger(); + + expect(state.totalSupply).toEqual(0n); + expect(state.name).toEqual(NO_STRING); + expect(state.symbol).toEqual(NO_STRING); + expect(state.decimals).toEqual(0n); + }); + }); + + describe('approve', () => { + // TODO: change caller context to test IERC20 interface + it.skip('should approve', () => { + const initAllowance = token.allowance(OWNER, SPENDER); + expect(initAllowance).toEqual(0n); + + token._mint(OWNER, AMOUNT); + token.approve(SPENDER, AMOUNT); + }); + }) + + describe('_approve', () => { + it('should _approve', () => { + const initAllowance = token.allowance(OWNER, SPENDER); + expect(initAllowance).toEqual(0n); + + token._approve(OWNER, SPENDER, AMOUNT); + + expect(token.allowance(OWNER, SPENDER)).toEqual(initAllowance + AMOUNT); + }); + + it('should approve to a new spender address', () => { + token._approve(OWNER, SPENDER, AMOUNT); + expect(token.allowance(OWNER, SPENDER)).toEqual(AMOUNT); + + const NEW_SPENDER = utils.createEitherTestUser('NEW_SPENDER'); + const newAmount = AMOUNT + 200n; + expect(token.allowance(OWNER, NEW_SPENDER)).toEqual(0n); + token._approve(OWNER, NEW_SPENDER, newAmount); + + expect(token.allowance(OWNER, NEW_SPENDER)).toEqual(newAmount); + expect(token.allowance(OWNER, SPENDER)).toEqual(AMOUNT); + }); + + it('should throw when owner is zero', () => { + expect(() => { + token._approve(utils.ZERO_KEY, SPENDER, AMOUNT); + }).toThrow('ERC20: invalid owner'); + }); + + it('should throw when spender is zero', () => { + expect(() => { + token._approve(OWNER, utils.ZERO_KEY, AMOUNT); + }).toThrow('ERC20: invalid spender'); + }); + }); + + describe('_spendAllowance', () => { + describe('spend allowance when not infinite', () => { + beforeEach(() => { + token._approve(OWNER, SPENDER, AMOUNT); + expect(token.allowance(OWNER, SPENDER)).toEqual(AMOUNT); + }) + + it('spends allowance', () => { + token._spendAllowance(OWNER, SPENDER, AMOUNT); + expect(token.allowance(OWNER, SPENDER)).toEqual(0n); + }); + + it('spends partial allowance', () => { + const partialAllowance = AMOUNT - 1n; + token._spendAllowance(OWNER, SPENDER, partialAllowance); + expect(token.allowance(OWNER, SPENDER)).toEqual(1n); + }); + + it('throws when not enough allowance', () => { + expect(() => { + token._spendAllowance(OWNER, SPENDER, AMOUNT + 1n); + }).toThrow('ERC20: insufficient allowance'); + }); + }); + + describe('infinite allowance', () => { + beforeEach(() => { + token._approve(OWNER, SPENDER, MAX_UINT256); + expect(token.allowance(OWNER, SPENDER)).toEqual(MAX_UINT256); + }); + + it('should not subtract from infinite allowance', () => { + token._spendAllowance(OWNER, SPENDER, MAX_UINT256 - 1n); + + expect(token.allowance(OWNER, SPENDER)).toEqual(MAX_UINT256); + }); + }); + }); + + describe('transferFrom', () => { + beforeEach(() => { + token._mint(OWNER, AMOUNT); + }); + + it.skip('should transfer from owner to recipient', () => { + const ownerBal = token.balanceOf(OWNER); + const recipientBal = token.balanceOf(RECIPIENT); + + token.transferFrom(OWNER, RECIPIENT, AMOUNT); + }) + }) + + describe('transfer', () => { + beforeEach(() => { + token._mint(OWNER, AMOUNT); + }); + + describe('internal _transfer', () => { + it('should _transfer', () => { + const ownerBal = token.balanceOf(OWNER); + const recipientBal = token.balanceOf(RECIPIENT); + + token._transfer(OWNER, RECIPIENT, AMOUNT); + + expect(token.balanceOf(OWNER)).toEqual(ownerBal - AMOUNT); + expect(token.balanceOf(RECIPIENT)).toEqual(recipientBal + AMOUNT); + + // Confirm totalSupply doesn't change + expect(token.getLedger().totalSupply).toEqual(AMOUNT); + }); + + it('throws when _transfer with not enough balance', () => { + expect(() => { + token._transfer(OWNER, RECIPIENT, AMOUNT + 1n); + }).toThrow('ERC20: insufficient balance'); + }); + }); + }); + + describe('mint', () => { + it('should mint and update supply', () => { + const initSupply = token.getLedger().totalSupply; + expect(initSupply).toEqual(0n); + + token._mint(RECIPIENT, AMOUNT); + expect(token.getLedger().totalSupply).toEqual(AMOUNT); + expect(token.balanceOf(RECIPIENT)).toEqual(AMOUNT); + }); + + it('should not mint to zero pubkey', () => { + expect(() => { + token._mint(utils.ZERO_KEY, AMOUNT); + }).toThrow('ERC20: invalid receiver'); + }); + + it('should not mint to zero contract address', () => { + expect(() => { + token._mint(utils.ZERO_ADDRESS, AMOUNT); + }).toThrow('ERC20: invalid receiver'); + }); + }); + + describe('burn', () => { + beforeEach(() => { + token._mint(OWNER, AMOUNT); + }); + + it('should burn tokens', () => { + token._burn(OWNER, 1n); + + const afterBurn = AMOUNT - 1n; + expect(token.balanceOf(OWNER)).toEqual(afterBurn); + expect(token.getLedger().totalSupply).toEqual(afterBurn) + }); + + it('should throw when burning from zero', () => { + expect(() => { + token._burn(utils.ZERO_KEY, AMOUNT); + }).toThrow('ERC20: invalid sender'); + }); + + it('should throw when burn amount is greater than balance', () => { + expect(() => { + token._burn(OWNER, AMOUNT + 1n); + }).toThrow('ERC20: insufficient balance'); + }); + }); + + describe('_update', () => { + it('should update from zero to non-zero (mint)', () => { + expect(token.getLedger().totalSupply).toEqual(0n); + expect(token.balanceOf(OWNER)).toEqual(0n); + + token._update(utils.ZERO_KEY, OWNER, AMOUNT); + + expect(token.getLedger().totalSupply).toEqual(AMOUNT); + expect(token.balanceOf(OWNER)).toEqual(AMOUNT); + }); + + describe('with minted tokens', () => { + beforeEach(() => { + token._update(utils.ZERO_ADDRESS, OWNER, AMOUNT); + + expect(token.getLedger().totalSupply).toEqual(AMOUNT); + expect(token.balanceOf(OWNER)).toEqual(AMOUNT); + }); + + it('should update from non-zero to zero (burn)', () => { + token._update(OWNER, utils.ZERO_ADDRESS, AMOUNT); + + expect(token.getLedger().totalSupply).toEqual(0n); + expect(token.balanceOf(OWNER)).toEqual(0n); + }); + + it('should update from non-zero to non-zero (transfer)', () => { + token._update(OWNER, RECIPIENT, AMOUNT - 1n); + + expect(token.getLedger().totalSupply).toEqual(AMOUNT); + expect(token.balanceOf(OWNER)).toEqual(1n); + expect(token.balanceOf(RECIPIENT)).toEqual(AMOUNT - 1n); + }); + }); + }); +}); diff --git a/contracts/erc721/contract/src/test/types.ts b/contracts/erc721/contract/src/test/types.ts new file mode 100644 index 00000000..4735fab2 --- /dev/null +++ b/contracts/erc721/contract/src/test/types.ts @@ -0,0 +1,4 @@ +export type MaybeString = { + is_some: boolean, + value: string +} diff --git a/contracts/erc721/contract/src/test/utils.ts b/contracts/erc721/contract/src/test/utils.ts new file mode 100644 index 00000000..1e060552 --- /dev/null +++ b/contracts/erc721/contract/src/test/utils.ts @@ -0,0 +1,78 @@ +import { encodeContractAddress } from '@midnight-ntwrk/ledger'; +import * as Compact from '../artifacts/erc721/contract/index.cjs'; +import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; + +const PREFIX_ADDRESS = "0200"; + +export const pad = (s: string, n: number): Uint8Array => { + const encoder = new TextEncoder(); + const utf8Bytes = encoder.encode(s); + if (n < utf8Bytes.length) { + throw new Error(`The padded length n must be at least ${utf8Bytes.length}`); + } + const paddedArray = new Uint8Array(n); + paddedArray.set(utf8Bytes); + return paddedArray; +} + +/** + * @description Generates ZswapCoinPublicKey from `str` for testing purposes. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { + const toHex = Buffer.from(str, 'ascii').toString('hex'); + return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; +} + +/** + * @description Generates ContractAddress from `str` for testing purposes. + * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToAddress = (str: string): Compact.ContractAddress => { + const toHex = Buffer.from(str, 'ascii').toString('hex'); + const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); + return { bytes: encodeContractAddress(fullAddress) }; +} + +/** + * @description Generates an Either object for ZswapCoinPublicKey for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ZswapCoinPublicKey. + */ +export const createEitherTestUser = (str: string) => { + return { + is_left: true, + left: encodeToPK(str), + right: encodeToAddress('') + } +} + +/** + * @description Generates an Either object for ContractAddress for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ContractAddress. + */ +export const createEitherTestContractAddress = (str: string) => { + return { + is_left: false, + left: encodeToPK(''), + right: encodeToAddress(str) + } +} + +export const ZERO_KEY = { + is_left: true, + left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, + right: encodeToAddress('') +} + +export const ZERO_ADDRESS = { + is_left: false, + left: encodeToPK(''), + right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) } +} diff --git a/contracts/erc721/contract/src/witnesses.ts b/contracts/erc721/contract/src/witnesses.ts new file mode 100644 index 00000000..b66d496b --- /dev/null +++ b/contracts/erc721/contract/src/witnesses.ts @@ -0,0 +1,7 @@ +// This is how we type an empty object. +export type ERC721PrivateState = Record; + +export const witnesses = {}; + +export const createERC721PrivateState = () => ({ +}); diff --git a/contracts/erc721/contract/tsconfig.build.json b/contracts/erc721/contract/tsconfig.build.json new file mode 100644 index 00000000..f1132509 --- /dev/null +++ b/contracts/erc721/contract/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["src/test/**/*.ts"], + "compilerOptions": {} +} diff --git a/contracts/erc721/contract/tsconfig.json b/contracts/erc721/contract/tsconfig.json new file mode 100644 index 00000000..3e90b0a9 --- /dev/null +++ b/contracts/erc721/contract/tsconfig.json @@ -0,0 +1,21 @@ +{ + "include": ["src/**/*.ts"], + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "lib": ["ESNext"], + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "node", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": true, + "strict": true, + "isolatedModules": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true + } +} diff --git a/package.json b/package.json index 37ced52f..046698e9 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "workspaces": [ "compact", "contracts/initializable/*", - "contracts/erc20/*" + "contracts/erc20/*", + "contracts/erc721/*" ], "scripts": { "compact": "turbo run compact", diff --git a/yarn.lock b/yarn.lock index 41eecc37..f3dbce1c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1096,6 +1096,17 @@ __metadata: languageName: unknown linkType: soft +"@openzeppelin-midnight-contracts/erc721-contract@workspace:contracts/erc721/contract": + version: 0.0.0-use.local + resolution: "@openzeppelin-midnight-contracts/erc721-contract@workspace:contracts/erc721/contract" + dependencies: + "@midnight-ntwrk/compact": "workspace:*" + eslint: "npm:^8.52.0" + jest: "npm:^29.7.0" + typescript: "npm:^5.2.2" + languageName: unknown + linkType: soft + "@openzeppelin-midnight-contracts/initializable-contract@workspace:contracts/initializable/contract": version: 0.0.0-use.local resolution: "@openzeppelin-midnight-contracts/initializable-contract@workspace:contracts/initializable/contract" From 951423db30a5d98be74965a4e553597a75ebf7a1 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 20:16:38 -0500 Subject: [PATCH 003/282] catch mint overflow to output a more readable error msg --- contracts/erc20/contract/src/ERC20.compact | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/contracts/erc20/contract/src/ERC20.compact b/contracts/erc20/contract/src/ERC20.compact index eb1c2054..49063624 100644 --- a/contracts/erc20/contract/src/ERC20.compact +++ b/contracts/erc20/contract/src/ERC20.compact @@ -245,6 +245,7 @@ module ERC20 { /** * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` * (or `to`) is the zero address. + * @dev Checks for a mint overflow in order to output a more readable error message. * * @param {from} - The original owner of the tokens moved (which is 0 if tokens are minted). * @param {to} - The recipient of the tokens moved (which is 0 if tokens are burned). @@ -258,6 +259,9 @@ module ERC20 { ): [] { if (isZero(from)) { // Mint + const MAX_UINT128 = 340282366920938463463374607431768211455; + assert MAX_UINT128 - _totalSupply >= value "ERC20: arithmetic overflow"; + _totalSupply = _totalSupply + value as Uint<128>; } else { const fromBal = balanceOf(from); @@ -270,7 +274,7 @@ module ERC20 { _totalSupply = _totalSupply - value as Uint<128>; } else { const toBal = balanceOf(to); - _balances.insert(to, toBal + value as Uint<128>); + _balances.insert(to, toBal + value as Uint<128>); } } @@ -293,8 +297,8 @@ module ERC20 { const currentAllowance = _allowances.lookup(owner).lookup(spender); // TODO: improve readability of max_u128 - const max_u128 = 340282366920938463463374607431768211455; - if (currentAllowance < max_u128) { + const MAX_UINT128 = 340282366920938463463374607431768211455; + if (currentAllowance < MAX_UINT128) { assert currentAllowance >= value "ERC20: insufficient allowance"; _approve(owner, spender, currentAllowance - value as Uint<128>); } From 9486458ea994c45e3ab35425ae2892c5f931a90e Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 20:17:02 -0500 Subject: [PATCH 004/282] add overflow tests --- .../erc20/contract/src/test/erc20.test.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/contracts/erc20/contract/src/test/erc20.test.ts b/contracts/erc20/contract/src/test/erc20.test.ts index a77ae72d..dd06ecc6 100644 --- a/contracts/erc20/contract/src/test/erc20.test.ts +++ b/contracts/erc20/contract/src/test/erc20.test.ts @@ -343,6 +343,14 @@ describe('ERC20', () => { expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); }); + it('should catch mint overflow', () => { + token._mint(Z_RECIPIENT, MAX_UINT128); + + expect(() => { + token._mint(Z_RECIPIENT, 1n); + }).toThrow('ERC20: arithmetic overflow'); + }); + it('should not mint to zero pubkey', () => { expect(() => { token._mint(utils.ZERO_KEY, AMOUNT); @@ -405,6 +413,14 @@ describe('ERC20', () => { expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); }); + it('should catch overflow from zero to non-zero (mint)', () => { + token._update(utils.ZERO_KEY, Z_OWNER, MAX_UINT128); + + expect(() => { + token._update(utils.ZERO_KEY, Z_OWNER, 1n); + }).toThrow('ERC20: arithmetic overflow'); + }); + describe('with minted tokens', () => { beforeEach(() => { token._update(utils.ZERO_ADDRESS, Z_OWNER, AMOUNT); @@ -420,6 +436,14 @@ describe('ERC20', () => { expect(token.balanceOf(Z_OWNER)).toEqual(0n); }); + it('should catch overflow from non-zero to zero (burn)', () => { + token._update(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); + + expect(() => { + token._update(Z_OWNER, utils.ZERO_ADDRESS, 1n); + }).toThrow('ERC20: insufficient balance'); + }); + it('should update from non-zero to non-zero (transfer)', () => { token._update(Z_OWNER, Z_RECIPIENT, AMOUNT - 1n); From df976ee343b0b2533a0ac1b970414a360bb1fd06 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 5 Apr 2025 17:21:18 -0500 Subject: [PATCH 005/282] fix test assertions --- .../erc20/contract/src/test/erc20.test.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/contracts/erc20/contract/src/test/erc20.test.ts b/contracts/erc20/contract/src/test/erc20.test.ts index dd06ecc6..628ecd0d 100644 --- a/contracts/erc20/contract/src/test/erc20.test.ts +++ b/contracts/erc20/contract/src/test/erc20.test.ts @@ -98,7 +98,7 @@ describe('ERC20', () => { caller = OWNER; const txSuccess = token.transfer(Z_RECIPIENT, partialAmt, caller); - expect(txSuccess).toBeTruthy; + expect(txSuccess).toBeTruthy(); expect(token.balanceOf(Z_OWNER)).toEqual(1n); expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); }); @@ -107,7 +107,7 @@ describe('ERC20', () => { caller = OWNER; const txSuccess = token.transfer(Z_RECIPIENT, AMOUNT, caller); - expect(txSuccess).toBeTruthy; + expect(txSuccess).toBeTruthy(); expect(token.balanceOf(Z_OWNER)).toEqual(0n); expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); }); @@ -146,7 +146,7 @@ describe('ERC20', () => { it('should handle transfer with empty _balances', () => { caller = SPENDER; - + expect(() => { token.transfer(Z_RECIPIENT, 1n, caller); }).toThrow('ERC20: insufficient balance'); @@ -235,7 +235,7 @@ describe('ERC20', () => { const partialAmt = AMOUNT - 1n; const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, partialAmt, caller); - expect(txSuccess).toBeTruthy; + expect(txSuccess).toBeTruthy(); // Check balances expect(token.balanceOf(Z_OWNER)).toEqual(1n); @@ -248,7 +248,7 @@ describe('ERC20', () => { caller = SPENDER; const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - expect(txSuccess).toBeTruthy; + expect(txSuccess).toBeTruthy(); // Check balances expect(token.balanceOf(Z_OWNER)).toEqual(0n); @@ -263,7 +263,7 @@ describe('ERC20', () => { caller = SPENDER; const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - expect(txSuccess).toBeTruthy; + expect(txSuccess).toBeTruthy(); // Check balances expect(token.balanceOf(Z_OWNER)).toEqual(0n); @@ -456,13 +456,13 @@ describe('ERC20', () => { describe('isZero', () => { it('should return zero for the zero address', () => { - expect(token.isZero(utils.ZERO_KEY)).toBeTruthy; - expect(token.isZero(utils.ZERO_ADDRESS)).toBeTruthy; + expect(token.isZero(utils.ZERO_KEY)).toBeTruthy(); + expect(token.isZero(utils.ZERO_ADDRESS)).toBeTruthy(); }); it('should not return zero for nonzero addresses', () => { - expect(token.isZero(Z_OWNER)).toBeFalsy; - expect(token.isZero(SOME_CONTRACT)).toBeFalsy; + expect(token.isZero(Z_OWNER)).toBeFalsy(); + expect(token.isZero(SOME_CONTRACT)).toBeFalsy(); }); }); From 3015a817df8e9ed5b9ad88fcd9b6590c90e664a1 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 5 Apr 2025 17:43:09 -0500 Subject: [PATCH 006/282] add initial module doc --- contracts/erc20/contract/src/ERC20.compact | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/contracts/erc20/contract/src/ERC20.compact b/contracts/erc20/contract/src/ERC20.compact index 49063624..861ca5e9 100644 --- a/contracts/erc20/contract/src/ERC20.compact +++ b/contracts/erc20/contract/src/ERC20.compact @@ -2,6 +2,24 @@ pragma language_version >= 0.14.0; +/** + * @module ERC20 + * @description An unshielded ERC20 library. + * + * @notice One notable difference regarding this implementation and the EIP20 spec + * consists of the token size. Uint<128> is used as the token size because Uint<256> + * cannot be supported. + * This is due to encoding limits on the midnight circuit backend: + * https://github.com/midnightntwrk/compactc/issues/929 + * + * @notice Further discussion and consideration required: + * + * - Consider changing the underscore in the internal methods to `unsafe` or + * adopting dot notation for prefixing imports. + * - Revise logic once contract-to-contract interactions are available on midnight. + * - Consider implementing an introspection mechanism for transfers to contracts. + * - Standardize which zero address to use (`ZswapCoinPublicKey` or `ContractAddress`). + */ module ERC20 { import CompactStandardLibrary; From 44780b3f0af5a98870e87f5335f92f72ef2fb45c Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 3 Apr 2025 23:59:27 -0500 Subject: [PATCH 007/282] add utils package --- contracts/erc20/contract/package.json | 3 + contracts/erc20/contract/src/ERC20.compact | 34 +- contracts/utils/contract/.eslintignore | 1 + contracts/utils/contract/.eslintrc.cjs | 30 ++ contracts/utils/contract/jest.config.ts | 28 ++ contracts/utils/contract/js-resolver.cjs | 16 + contracts/utils/contract/package.json | 29 ++ .../utils/contract/src/MockUtils.compact | 13 + contracts/utils/contract/src/Utils.compact | 24 ++ .../utils/contract/src/test/UtilsSimulator.ts | 308 ++++++++++++++++++ contracts/utils/contract/src/test/types.ts | 4 + .../utils/contract/src/test/utils.test.ts | 23 ++ contracts/utils/contract/src/test/utils.ts | 78 +++++ contracts/utils/contract/src/types/index.ts | 1 + contracts/utils/contract/src/types/test.ts | 23 ++ contracts/utils/contract/src/utils/index.ts | 1 + contracts/utils/contract/src/utils/test.ts | 67 ++++ .../contract/src/witnesses/UtilsWitnesses.ts | 7 + .../utils/contract/src/witnesses/index.ts | 2 + contracts/utils/contract/tsconfig.build.json | 5 + contracts/utils/contract/tsconfig.json | 21 ++ package.json | 3 +- yarn.lock | 12 + 23 files changed, 707 insertions(+), 26 deletions(-) create mode 100644 contracts/utils/contract/.eslintignore create mode 100644 contracts/utils/contract/.eslintrc.cjs create mode 100644 contracts/utils/contract/jest.config.ts create mode 100644 contracts/utils/contract/js-resolver.cjs create mode 100644 contracts/utils/contract/package.json create mode 100644 contracts/utils/contract/src/MockUtils.compact create mode 100644 contracts/utils/contract/src/Utils.compact create mode 100644 contracts/utils/contract/src/test/UtilsSimulator.ts create mode 100644 contracts/utils/contract/src/test/types.ts create mode 100644 contracts/utils/contract/src/test/utils.test.ts create mode 100644 contracts/utils/contract/src/test/utils.ts create mode 100644 contracts/utils/contract/src/types/index.ts create mode 100644 contracts/utils/contract/src/types/test.ts create mode 100644 contracts/utils/contract/src/utils/index.ts create mode 100644 contracts/utils/contract/src/utils/test.ts create mode 100644 contracts/utils/contract/src/witnesses/UtilsWitnesses.ts create mode 100644 contracts/utils/contract/src/witnesses/index.ts create mode 100644 contracts/utils/contract/tsconfig.build.json create mode 100644 contracts/utils/contract/tsconfig.json diff --git a/contracts/erc20/contract/package.json b/contracts/erc20/contract/package.json index 345721eb..d914daf0 100644 --- a/contracts/erc20/contract/package.json +++ b/contracts/erc20/contract/package.json @@ -20,6 +20,9 @@ "lint": "eslint src", "typecheck": "tsc -p tsconfig.json --noEmit" }, + "dependencies": { + "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" + }, "devDependencies": { "@midnight-ntwrk/compact": "workspace:*", "eslint": "^8.52.0", diff --git a/contracts/erc20/contract/src/ERC20.compact b/contracts/erc20/contract/src/ERC20.compact index 861ca5e9..ea7775eb 100644 --- a/contracts/erc20/contract/src/ERC20.compact +++ b/contracts/erc20/contract/src/ERC20.compact @@ -22,6 +22,7 @@ pragma language_version >= 0.14.0; */ module ERC20 { import CompactStandardLibrary; + import "../node_modules/@openzeppelin-midnight-contracts/utils-contract/dist/Utils" prefix Utils_; /// Public state export ledger _name: Maybe>; @@ -191,8 +192,8 @@ module ERC20 { spender: Either, value: Uint<128> ): [] { - assert !isZero(owner) "ERC20: invalid owner"; - assert !isZero(spender) "ERC20: invalid spender"; + assert !Utils_isZero(owner) "ERC20: invalid owner"; + assert !Utils_isZero(spender) "ERC20: invalid spender"; if (!_allowances.member(owner)) { // If owner doesn't exist, create and insert a new sub-map directly _allowances.insert(owner, default, Uint<128>>>); @@ -215,8 +216,8 @@ module ERC20 { to: Either, value: Uint<128> ): [] { - assert !isZero(from) "ERC20: invalid sender"; - assert !isZero(to) "ERC20: invalid receiver"; + assert !Utils_isZero(from) "ERC20: invalid sender"; + assert !Utils_isZero(to) "ERC20: invalid receiver"; _update(from, to, value); } @@ -233,7 +234,7 @@ module ERC20 { account: Either, value: Uint<128> ): [] { - assert !isZero(account) "ERC20: invalid receiver"; + assert !Utils_isZero(account) "ERC20: invalid receiver"; // Using the contract variant of 0 // TODO: Look into if this matters const zero_address = right(ContractAddress{ pad(32, "") }); @@ -253,7 +254,7 @@ module ERC20 { account: Either, value: Uint<128> ): [] { - assert !isZero(account) "ERC20: invalid sender"; + assert !Utils_isZero(account) "ERC20: invalid sender"; // Using the contract variant of 0 // TODO: Look into if this matters const zero_address = right(ContractAddress{ pad(32, "") }); @@ -275,7 +276,7 @@ module ERC20 { to: Either, value: Uint<128> ): [] { - if (isZero(from)) { + if (Utils_isZero(from)) { // Mint const MAX_UINT128 = 340282366920938463463374607431768211455; assert MAX_UINT128 - _totalSupply >= value "ERC20: arithmetic overflow"; @@ -287,7 +288,7 @@ module ERC20 { _balances.insert(from, fromBal - value as Uint<128>); } - if (isZero(to)) { + if (Utils_isZero(to)) { // Burn _totalSupply = _totalSupply - value as Uint<128>; } else { @@ -321,21 +322,4 @@ module ERC20 { _approve(owner, spender, currentAllowance - value as Uint<128>); } } - - /** - * @description Returns whether `keyOrAddress` is the zero address. - * @todo Move to a utils contract since this will likely be reused. - * - * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. - * @return {Boolean} - Returns true if `keyOrAddress` is zero. - */ - export pure circuit isZero(keyOrAddress: Either): Boolean { - const zero = pad(32, ""); - - if (keyOrAddress.is_left) { - return keyOrAddress == left(ZswapCoinPublicKey{ zero }); - } else { - return keyOrAddress == right(ContractAddress{ zero }); - } - } } diff --git a/contracts/utils/contract/.eslintignore b/contracts/utils/contract/.eslintignore new file mode 100644 index 00000000..652df825 --- /dev/null +++ b/contracts/utils/contract/.eslintignore @@ -0,0 +1 @@ +src/managed diff --git a/contracts/utils/contract/.eslintrc.cjs b/contracts/utils/contract/.eslintrc.cjs new file mode 100644 index 00000000..581f1d49 --- /dev/null +++ b/contracts/utils/contract/.eslintrc.cjs @@ -0,0 +1,30 @@ +module.exports = { + env: { + browser: true, + es2021: true, + node: true, + jest: true, + }, + extends: [ + 'standard-with-typescript', + 'plugin:prettier/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + ], + overrides: [], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['tsconfig.json'], + }, + rules: { + '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 + '@typescript-eslint/no-floating-promises': 'warn', + '@typescript-eslint/promise-function-async': 'off', + '@typescript-eslint/no-redeclare': 'off', + '@typescript-eslint/no-invalid-void-type': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/consistent-type-definitions': 'off' + }, +}; diff --git a/contracts/utils/contract/jest.config.ts b/contracts/utils/contract/jest.config.ts new file mode 100644 index 00000000..edbdaeba --- /dev/null +++ b/contracts/utils/contract/jest.config.ts @@ -0,0 +1,28 @@ +import type { Config } from "@jest/types"; + +const config: Config.InitialOptions = { + preset: "ts-jest/presets/default-esm", + testEnvironment: "node", + verbose: true, + roots: [""], + modulePaths: [""], + passWithNoTests: false, + testMatch: ["**/*.test.ts"], + extensionsToTreatAsEsm: [".ts"], + collectCoverage: true, + resolver: '/js-resolver.cjs', + coverageThreshold: { + global: { + //branches: 60, + //functions: 75, + //lines: 70, + }, + }, + reporters: [ + "default", + ["jest-junit", { outputDirectory: "reports", outputName: "report.xml" }], + ["jest-html-reporters", { publicPath: "reports", filename: "report.html" }], + ], +}; + +export default config; diff --git a/contracts/utils/contract/js-resolver.cjs b/contracts/utils/contract/js-resolver.cjs new file mode 100644 index 00000000..cc9ed285 --- /dev/null +++ b/contracts/utils/contract/js-resolver.cjs @@ -0,0 +1,16 @@ +const jsResolver = (path, options) => { + const jsExtRegex = /\.js$/i + const resolver = options.defaultResolver + if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { + const newPath = path.replace(jsExtRegex, '.ts'); + try { + return resolver(newPath, options) + } catch { + // use default resolver + } + } + + return resolver(path, options) +} + +module.exports = jsResolver diff --git a/contracts/utils/contract/package.json b/contracts/utils/contract/package.json new file mode 100644 index 00000000..40c57157 --- /dev/null +++ b/contracts/utils/contract/package.json @@ -0,0 +1,29 @@ +{ + "name": "@openzeppelin-midnight-contracts/utils-contract", + "type": "module", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "scripts": { + "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", + "test": "NODE_OPTIONS=--experimental-vm-modules jest", + "prepack": "yarn build", + "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/Utils.compact ./dist", + "lint": "eslint src", + "typecheck": "tsc -p tsconfig.json --noEmit" + }, + "devDependencies": { + "@midnight-ntwrk/compact": "workspace:*", + "eslint": "^8.52.0", + "jest": "^29.7.0", + "typescript": "^5.2.2" + } +} diff --git a/contracts/utils/contract/src/MockUtils.compact b/contracts/utils/contract/src/MockUtils.compact new file mode 100644 index 00000000..e23c0f09 --- /dev/null +++ b/contracts/utils/contract/src/MockUtils.compact @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.14.0; + +import CompactStandardLibrary; + +import Utils prefix Utils_; + +export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; + +export pure circuit isZero(keyOrAddress: Either): Boolean { + return Utils_isZero(keyOrAddress); +} diff --git a/contracts/utils/contract/src/Utils.compact b/contracts/utils/contract/src/Utils.compact new file mode 100644 index 00000000..b0dbf3f5 --- /dev/null +++ b/contracts/utils/contract/src/Utils.compact @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.14.0; + +module Utils { + import CompactStandardLibrary; + + /** + * @description Returns whether `keyOrAddress` is the zero address. + * @todo Move to a utils contract since this will likely be reused. + * + * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @return {Boolean} - Returns true if `keyOrAddress` is zero. + */ + export pure circuit isZero(keyOrAddress: Either): Boolean { + const zero = pad(32, ""); + + if (keyOrAddress.is_left) { + return keyOrAddress == left(ZswapCoinPublicKey{ zero }); + } else { + return keyOrAddress == right(ContractAddress{ zero }); + } + } +} diff --git a/contracts/utils/contract/src/test/UtilsSimulator.ts b/contracts/utils/contract/src/test/UtilsSimulator.ts new file mode 100644 index 00000000..34995957 --- /dev/null +++ b/contracts/utils/contract/src/test/UtilsSimulator.ts @@ -0,0 +1,308 @@ +import { + type CircuitContext, + CoinPublicKey, + type ContractState, + QueryContext, + constructorContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import { sampleContractAddress } from '@midnight-ntwrk/zswap'; +import { + type Ledger, + Contract as MockUtils, + ledger, + Either, + ZswapCoinPublicKey, + ContractAddress, +} from '../artifacts/MockUtils/contract/index.cjs'; // Combined imports +import { MaybeString } from './types.js'; +import type { IContractSimulator } from '../types/index.js'; +import { UtilsPrivateState, UtilsWitnesses } from '../witnesses/index.js'; + +/** + * @description A simulator implementation of an utils contract for testing purposes. + * @template P - The private state type, fixed to UtilsPrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class UtilsContractSimulator + implements IContractSimulator +{ + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockUtils; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor() { + this.contract = new MockUtils( + UtilsWitnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)) + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type UtilsPrivateState. + */ + public getCurrentPrivateState(): UtilsPrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + +// /** +// * @description Returns the token name. +// * @returns The token name. +// */ +// public name(): MaybeString { +// return this.contract.impureCircuits.name(this.circuitContext).result; +// } +// +// /** +// * @description Returns the symbol of the token. +// * @returns The token name. +// */ +// public symbol(): MaybeString { +// return this.contract.impureCircuits.symbol(this.circuitContext).result; +// } +// +// /** +// * @description Returns the number of decimals used to get its user representation. +// * @returns The account's token balance. +// */ +// public decimals(): bigint { +// return this.contract.impureCircuits.decimals(this.circuitContext).result; +// } +// +// /** +// * @description Returns the value of tokens in existence. +// * @returns The total supply of tokens. +// */ +// public totalSupply(): bigint { +// return this.contract.impureCircuits.totalSupply(this.circuitContext).result; +// } +// +// /** +// * @description Returns the value of tokens owned by `account`. +// * @param account The public key or contract address to query. +// * @returns The account's token balance. +// */ +// public balanceOf(account: Either): bigint { +// return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; +// } +// +// /** +// * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` +// * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. +// * @param owner The public key or contract address of approver. +// * @param spender The public key or contract address of spender. +// * @returns The `spender`'s allowance over `owner`'s tokens. +// */ +// public allowance( +// owner: Either, +// spender: Either +// ): bigint { +// return this.contract.impureCircuits.allowance(this.circuitContext, owner, spender).result; +// } +// +// /** +// * @description Moves a `value` amount of tokens from the caller's account to `to`. +// * @param to The recipient of the transfer, either a user or a contract. +// * @param value The amount to transfer. +// * @param sender The simulated caller. +// * @returns As per the IUtils spec, this MUST return true. +// */ +// public transfer(to: Either, value: bigint, sender?: CoinPublicKey): boolean { +// const res = this.contract.impureCircuits.transfer({ +// ...this.circuitContext, +// currentZswapLocalState: sender +// ? emptyZswapLocalState(sender) +// : this.circuitContext.currentZswapLocalState, +// }, to, value +// ); +// +// this.circuitContext = res.context; +// return res.result; +// } +// +// /** +// * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. +// * `value` is the deducted from the caller's allowance. +// * @param from The current owner of the tokens for the transfer, either a user or a contract. +// * @param to The recipient of the transfer, either a user or a contract. +// * @param value The amount to transfer. +// * @param sender The simulated caller. +// * @returns As per the IUtils spec, this MUST return true. +// */ +// public transferFrom( +// from: Either, +// to: Either, +// value: bigint, +// sender?: CoinPublicKey +// ): boolean { +// const res = this.contract.impureCircuits.transferFrom({ +// ...this.circuitContext, +// currentZswapLocalState: sender +// ? emptyZswapLocalState(sender) +// : this.circuitContext.currentZswapLocalState, +// }, +// from, to, value +// ); +// +// this.circuitContext = res.context; +// return res.result; +// } +// +// /** +// * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. +// * @param spender The Zswap key or ContractAddress that may spend on behalf of the caller. +// * @param value The amount of tokens the `spender` may spend. +// * @param sender The simulated caller. +// * @returns Returns a boolean value indicating whether the operation succeeded. +// */ +// public approve(spender: Either, value: bigint, sender?: CoinPublicKey): boolean { +// const res = this.contract.impureCircuits.approve({ +// ...this.circuitContext, +// currentZswapLocalState: sender +// ? emptyZswapLocalState(sender) +// : this.circuitContext.currentZswapLocalState, +// }, +// spender, value +// ); +// +// this.circuitContext = res.context; +// return res.result; +// } +// +// /// +// /// Internal +// /// +// +// /** +// * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. +// * This internal function is equivalent to `approve`, and can be used to +// * e.g. set automatic allowances for certain subsystems, etc. +// * @param owner The owner of the tokens. +// * @param spender The spender of the tokens. +// * @param value The amount of tokens `spender` may spend on behalf of `owner`. +// * @returns None. +// */ +// public _approve( +// owner: Either, +// spender: Either, +// value: bigint +// ) { +// this.circuitContext = this.contract.impureCircuits._approve(this.circuitContext, owner, spender, value).context; +// } +// +// /** +// * @description Moves a `value` amount of tokens from `from` to `to`. +// * This internal function is equivalent to {transfer}, and can be used to +// * e.g. implement automatic token fees, slashing mechanisms, etc. +// * @param from The owner of the tokens to transfer. +// * @param to The receipient of the transferred tokens. +// * @param value The amount of tokens to transfer. +// */ +// public _transfer( +// from: Either, +// to: Either, +// value: bigint, +// ) { +// this.circuitContext = this.contract.impureCircuits._transfer(this.circuitContext, from, to, value).context; +// } +// +// /** +// * @description Creates a `value` amount of tokens and assigns them to `account`, +// * by transferring it from the zero address. Relies on the `update` mechanism. +// * @param account The recipient of tokens minted. +// * @param value The amount of tokens minted. +// */ +// public _mint(account: Either, value: bigint) { +// this.circuitContext = this.contract.impureCircuits._mint(this.circuitContext, account, value).context; +// } +// +// /** +// * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. +// * Relies on the `_update` mechanism. +// * @param account The target owner of tokens to burn. +// * @param value The amount of tokens to burn. +// */ +// public _burn(account: Either, value: bigint) { +// this.circuitContext = this.contract.impureCircuits._burn(this.circuitContext, account, value).context; +// } +// +// /** +// * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` +// * (or `to`) is the zero address. +// * @param from The original owner of the tokens moved (which is 0 if tokens are minted). +// * @param to The recipient of the tokens moved (which is 0 if tokens are burned). +// * @param value The amount of tokens moved from `from` to `to`. +// */ +// public _update( +// from: Either, +// to: Either, +// value: bigint +// ) { +// this.circuitContext = this.contract.impureCircuits._update(this.circuitContext, from, to, value).context; +// } +// +// /** +// * @description Updates `owner`'s allowance for `spender` based on spent `value`. +// * Does not update the allowance value in case of infinite allowance. +// * @param owner The owner of the tokens. +// * @param spender The spender of the tokens. +// * @param value The amount of token allowance to spend. +// */ +// public _spendAllowance( +// owner: Either, +// spender: Either, +// value: bigint +// ) { +// this.circuitContext = this.contract.impureCircuits._spendAllowance(this.circuitContext, owner, spender, value).context; +// } +// + /** + * @description Returns whether `keyOrAddress` is the zero address. + * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @returns Returns true if `keyOrAddress` is zero. + */ + public isZero(keyOrAddress: Either): boolean { + return this.contract.circuits.isZero(this.circuitContext, keyOrAddress).result; + } +} diff --git a/contracts/utils/contract/src/test/types.ts b/contracts/utils/contract/src/test/types.ts new file mode 100644 index 00000000..4735fab2 --- /dev/null +++ b/contracts/utils/contract/src/test/types.ts @@ -0,0 +1,4 @@ +export type MaybeString = { + is_some: boolean, + value: string +} diff --git a/contracts/utils/contract/src/test/utils.test.ts b/contracts/utils/contract/src/test/utils.test.ts new file mode 100644 index 00000000..499ad79e --- /dev/null +++ b/contracts/utils/contract/src/test/utils.test.ts @@ -0,0 +1,23 @@ +import { UtilsContractSimulator } from './UtilsSimulator'; +import * as utils from './utils.js'; + +const Z_OWNER = utils.createEitherTestUser('OWNER'); +const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); + +let contract: UtilsContractSimulator; + +describe('Utils', () => { + contract = new UtilsContractSimulator(); + + describe('isZero', () => { + it('should return zero for the zero address', () => { + expect(contract.isZero(utils.ZERO_KEY)).toBeTruthy; + expect(contract.isZero(utils.ZERO_ADDRESS)).toBeTruthy; + }); + + it('should not return zero for nonzero addresses', () => { + expect(contract.isZero(Z_OWNER)).toBeFalsy; + expect(contract.isZero(SOME_CONTRACT)).toBeFalsy; + }); + }); +}); diff --git a/contracts/utils/contract/src/test/utils.ts b/contracts/utils/contract/src/test/utils.ts new file mode 100644 index 00000000..e360bda1 --- /dev/null +++ b/contracts/utils/contract/src/test/utils.ts @@ -0,0 +1,78 @@ +import { encodeContractAddress } from '@midnight-ntwrk/ledger'; +import * as Compact from '../artifacts/MockUtils/contract/index.cjs'; +import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; + +const PREFIX_ADDRESS = "0200"; + +export const pad = (s: string, n: number): Uint8Array => { + const encoder = new TextEncoder(); + const utf8Bytes = encoder.encode(s); + if (n < utf8Bytes.length) { + throw new Error(`The padded length n must be at least ${utf8Bytes.length}`); + } + const paddedArray = new Uint8Array(n); + paddedArray.set(utf8Bytes); + return paddedArray; +} + +/** + * @description Generates ZswapCoinPublicKey from `str` for testing purposes. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { + const toHex = Buffer.from(str, 'ascii').toString('hex'); + return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; +} + +/** + * @description Generates ContractAddress from `str` for testing purposes. + * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToAddress = (str: string): Compact.ContractAddress => { + const toHex = Buffer.from(str, 'ascii').toString('hex'); + const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); + return { bytes: encodeContractAddress(fullAddress) }; +} + +/** + * @description Generates an Either object for ZswapCoinPublicKey for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ZswapCoinPublicKey. + */ +export const createEitherTestUser = (str: string) => { + return { + is_left: true, + left: encodeToPK(str), + right: encodeToAddress('') + } +} + +/** + * @description Generates an Either object for ContractAddress for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ContractAddress. + */ +export const createEitherTestContractAddress = (str: string) => { + return { + is_left: false, + left: encodeToPK(''), + right: encodeToAddress(str) + } +} + +export const ZERO_KEY = { + is_left: true, + left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, + right: encodeToAddress('') +} + +export const ZERO_ADDRESS = { + is_left: false, + left: encodeToPK(''), + right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) } +} diff --git a/contracts/utils/contract/src/types/index.ts b/contracts/utils/contract/src/types/index.ts new file mode 100644 index 00000000..db642b5e --- /dev/null +++ b/contracts/utils/contract/src/types/index.ts @@ -0,0 +1 @@ +export type { IContractSimulator } from './test'; diff --git a/contracts/utils/contract/src/types/test.ts b/contracts/utils/contract/src/types/test.ts new file mode 100644 index 00000000..10fb6c98 --- /dev/null +++ b/contracts/utils/contract/src/types/test.ts @@ -0,0 +1,23 @@ +import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; + +/** + * Generic interface for mock contract implementations. + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + */ +export interface IContractSimulator { + /** The contract's deployed address. */ + readonly contractAddress: string; + + /** The current circuit context. */ + circuitContext: CircuitContext

; + + /** Retrieves the current ledger state. */ + getCurrentPublicState(): L; + + /** Retrieves the current private state. */ + getCurrentPrivateState(): P; + + /** Retrieves the current contract state. */ + getCurrentContractState(): ContractState; +} diff --git a/contracts/utils/contract/src/utils/index.ts b/contracts/utils/contract/src/utils/index.ts new file mode 100644 index 00000000..14e02ef2 --- /dev/null +++ b/contracts/utils/contract/src/utils/index.ts @@ -0,0 +1 @@ +export { useCircuitContext as circuitContext } from './test'; diff --git a/contracts/utils/contract/src/utils/test.ts b/contracts/utils/contract/src/utils/test.ts new file mode 100644 index 00000000..940ed612 --- /dev/null +++ b/contracts/utils/contract/src/utils/test.ts @@ -0,0 +1,67 @@ +import { + type CircuitContext, + type CoinPublicKey, + type ContractAddress, + type ContractState, + QueryContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import type { IContractSimulator } from '../types'; + +/** + * Constructs a `CircuitContext` from the given state and sender information. + * + * This is typically used at runtime to provide the necessary context + * for executing circuits, including contract state, private state, + * sender identity, and transaction data. + * + * @template P - The type of the contract's private state. + * @param privateState - The current private state of the contract. + * @param contractState - The full contract state, including public and private data. + * @param sender - The public key of the sender (used in the circuit). + * @param contractAddress - The address of the deployed contract. + * @returns A fully populated `CircuitContext` for circuit execution. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContext

( + privateState: P, + contractState: ContractState, + sender: CoinPublicKey, + contractAddress: ContractAddress, +): CircuitContext

{ + return { + originalState: contractState, + currentPrivateState: privateState, + transactionContext: new QueryContext(contractState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} + +/** + * Prepares a new `CircuitContext` using the given sender and contract. + * + * Useful for mocking or updating the circuit context with a custom sender. + * + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + * @template C - The specific type of the contract implementing `MockContract`. + * @param contract - The contract instance implementing `MockContract`. + * @param sender - The public key to set as the sender in the new circuit context. + * @returns A new `CircuitContext` with the sender and updated context values. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContextSender>( + contract: C, + sender: CoinPublicKey, +): CircuitContext

{ + const currentPrivateState = contract.getCurrentPrivateState(); + const originalState = contract.getCurrentContractState(); + const contractAddress = contract.contractAddress; + + return { + originalState, + currentPrivateState, + transactionContext: new QueryContext(originalState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} diff --git a/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts b/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts new file mode 100644 index 00000000..3b7d3340 --- /dev/null +++ b/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts @@ -0,0 +1,7 @@ +// This is how we type an empty object. +export type UtilsPrivateState = Record; + +export const witnesses = {}; +export const UtilsWitnesses = {}; + +export const createUtilsPrivateState = () => ({}); diff --git a/contracts/utils/contract/src/witnesses/index.ts b/contracts/utils/contract/src/witnesses/index.ts new file mode 100644 index 00000000..1c74ba34 --- /dev/null +++ b/contracts/utils/contract/src/witnesses/index.ts @@ -0,0 +1,2 @@ +export * from '../artifacts/utils/contract/index.cjs'; +export * from './UtilsWitnesses.js'; diff --git a/contracts/utils/contract/tsconfig.build.json b/contracts/utils/contract/tsconfig.build.json new file mode 100644 index 00000000..f1132509 --- /dev/null +++ b/contracts/utils/contract/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["src/test/**/*.ts"], + "compilerOptions": {} +} diff --git a/contracts/utils/contract/tsconfig.json b/contracts/utils/contract/tsconfig.json new file mode 100644 index 00000000..3e90b0a9 --- /dev/null +++ b/contracts/utils/contract/tsconfig.json @@ -0,0 +1,21 @@ +{ + "include": ["src/**/*.ts"], + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "lib": ["ESNext"], + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "node", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": true, + "strict": true, + "isolatedModules": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true + } +} diff --git a/package.json b/package.json index 046698e9..7c694a14 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "compact", "contracts/initializable/*", "contracts/erc20/*", - "contracts/erc721/*" + "contracts/erc721/*", + "contracts/utils/*" ], "scripts": { "compact": "turbo run compact", diff --git a/yarn.lock b/yarn.lock index f3dbce1c..cee6bf04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1090,6 +1090,7 @@ __metadata: resolution: "@openzeppelin-midnight-contracts/erc20-contract@workspace:contracts/erc20/contract" dependencies: "@midnight-ntwrk/compact": "workspace:*" + "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" eslint: "npm:^8.52.0" jest: "npm:^29.7.0" typescript: "npm:^5.2.2" @@ -1118,6 +1119,17 @@ __metadata: languageName: unknown linkType: soft +"@openzeppelin-midnight-contracts/utils-contract@workspace:^, @openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils/contract": + version: 0.0.0-use.local + resolution: "@openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils/contract" + dependencies: + "@midnight-ntwrk/compact": "workspace:*" + eslint: "npm:^8.52.0" + jest: "npm:^29.7.0" + typescript: "npm:^5.2.2" + languageName: unknown + linkType: soft + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" From 2c1fb05460aa62ca96a3b818d4e96ef2e8cdd088 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 00:12:22 -0500 Subject: [PATCH 008/282] add utils contract --- contracts/erc20/contract/package.json | 32 -- contracts/erc20/contract/src/ERC20.compact | 325 ------------ .../erc20/contract/src/MockERC20.compact | 110 ---- .../erc20/contract/src/test/ERC20Simulator.ts | 308 ----------- .../erc20/contract/src/test/erc20.test.ts | 485 ------------------ contracts/erc20/contract/src/types/index.ts | 1 - contracts/erc20/contract/src/utils/index.ts | 1 - .../contract/src/witnesses/ERC20Witnesses.ts | 7 - .../erc20/contract/src/witnesses/index.ts | 2 - .../{erc20/contract => utils}/.eslintignore | 0 .../{erc20/contract => utils}/.eslintrc.cjs | 0 contracts/utils/contract/.eslintignore | 1 - contracts/utils/contract/.eslintrc.cjs | 30 -- contracts/utils/contract/jest.config.ts | 28 - contracts/utils/contract/js-resolver.cjs | 16 - .../utils/contract/src/test/UtilsSimulator.ts | 308 ----------- contracts/utils/contract/src/test/types.ts | 4 - contracts/utils/contract/src/test/utils.ts | 78 --- contracts/utils/contract/src/types/index.ts | 1 - contracts/utils/contract/src/types/test.ts | 23 - contracts/utils/contract/src/utils/index.ts | 1 - contracts/utils/contract/src/utils/test.ts | 67 --- contracts/utils/contract/tsconfig.build.json | 5 - contracts/utils/contract/tsconfig.json | 21 - .../{erc20/contract => utils}/jest.config.ts | 0 .../{erc20/contract => utils}/js-resolver.cjs | 0 contracts/utils/{contract => }/package.json | 0 .../{contract => }/src/MockUtils.compact | 2 +- .../utils/{contract => }/src/Utils.compact | 0 contracts/utils/src/test/UtilsSimulator.ts | 94 ++++ .../src/test/types/index.ts} | 4 +- .../src => utils/src/test}/types/test.ts | 0 .../{contract => }/src/test/utils.test.ts | 10 +- .../src/test/utils/address.ts} | 2 +- contracts/utils/src/test/utils/index.ts | 4 + .../src => utils/src/test}/utils/test.ts | 0 .../src/witnesses/UtilsWitnesses.ts | 3 - .../{contract => }/src/witnesses/index.ts | 0 .../contract => utils}/tsconfig.build.json | 0 .../{erc20/contract => utils}/tsconfig.json | 0 yarn.lock | 11 - 41 files changed, 108 insertions(+), 1876 deletions(-) delete mode 100644 contracts/erc20/contract/package.json delete mode 100644 contracts/erc20/contract/src/ERC20.compact delete mode 100644 contracts/erc20/contract/src/MockERC20.compact delete mode 100644 contracts/erc20/contract/src/test/ERC20Simulator.ts delete mode 100644 contracts/erc20/contract/src/test/erc20.test.ts delete mode 100644 contracts/erc20/contract/src/types/index.ts delete mode 100644 contracts/erc20/contract/src/utils/index.ts delete mode 100644 contracts/erc20/contract/src/witnesses/ERC20Witnesses.ts delete mode 100644 contracts/erc20/contract/src/witnesses/index.ts rename contracts/{erc20/contract => utils}/.eslintignore (100%) rename contracts/{erc20/contract => utils}/.eslintrc.cjs (100%) delete mode 100644 contracts/utils/contract/.eslintignore delete mode 100644 contracts/utils/contract/.eslintrc.cjs delete mode 100644 contracts/utils/contract/jest.config.ts delete mode 100644 contracts/utils/contract/js-resolver.cjs delete mode 100644 contracts/utils/contract/src/test/UtilsSimulator.ts delete mode 100644 contracts/utils/contract/src/test/types.ts delete mode 100644 contracts/utils/contract/src/test/utils.ts delete mode 100644 contracts/utils/contract/src/types/index.ts delete mode 100644 contracts/utils/contract/src/types/test.ts delete mode 100644 contracts/utils/contract/src/utils/index.ts delete mode 100644 contracts/utils/contract/src/utils/test.ts delete mode 100644 contracts/utils/contract/tsconfig.build.json delete mode 100644 contracts/utils/contract/tsconfig.json rename contracts/{erc20/contract => utils}/jest.config.ts (100%) rename contracts/{erc20/contract => utils}/js-resolver.cjs (100%) rename contracts/utils/{contract => }/package.json (100%) rename contracts/utils/{contract => }/src/MockUtils.compact (81%) rename contracts/utils/{contract => }/src/Utils.compact (100%) create mode 100644 contracts/utils/src/test/UtilsSimulator.ts rename contracts/{erc20/contract/src/test/types.ts => utils/src/test/types/index.ts} (56%) rename contracts/{erc20/contract/src => utils/src/test}/types/test.ts (100%) rename contracts/utils/{contract => }/src/test/utils.test.ts (58%) rename contracts/{erc20/contract/src/test/utils.ts => utils/src/test/utils/address.ts} (97%) create mode 100644 contracts/utils/src/test/utils/index.ts rename contracts/{erc20/contract/src => utils/src/test}/utils/test.ts (100%) rename contracts/utils/{contract => }/src/witnesses/UtilsWitnesses.ts (85%) rename contracts/utils/{contract => }/src/witnesses/index.ts (100%) rename contracts/{erc20/contract => utils}/tsconfig.build.json (100%) rename contracts/{erc20/contract => utils}/tsconfig.json (100%) diff --git a/contracts/erc20/contract/package.json b/contracts/erc20/contract/package.json deleted file mode 100644 index d914daf0..00000000 --- a/contracts/erc20/contract/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "@openzeppelin-midnight-contracts/erc20-contract", - "type": "module", - "main": "dist/index.js", - "module": "dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "require": "./dist/index.js", - "import": "./dist/index.js", - "default": "./dist/index.js" - } - }, - "scripts": { - "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", - "test": "NODE_OPTIONS=--experimental-vm-modules jest", - "prepack": "yarn build", - "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/ERC20.compact ./dist", - "lint": "eslint src", - "typecheck": "tsc -p tsconfig.json --noEmit" - }, - "dependencies": { - "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" - }, - "devDependencies": { - "@midnight-ntwrk/compact": "workspace:*", - "eslint": "^8.52.0", - "jest": "^29.7.0", - "typescript": "^5.2.2" - } -} diff --git a/contracts/erc20/contract/src/ERC20.compact b/contracts/erc20/contract/src/ERC20.compact deleted file mode 100644 index ea7775eb..00000000 --- a/contracts/erc20/contract/src/ERC20.compact +++ /dev/null @@ -1,325 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.14.0; - -/** - * @module ERC20 - * @description An unshielded ERC20 library. - * - * @notice One notable difference regarding this implementation and the EIP20 spec - * consists of the token size. Uint<128> is used as the token size because Uint<256> - * cannot be supported. - * This is due to encoding limits on the midnight circuit backend: - * https://github.com/midnightntwrk/compactc/issues/929 - * - * @notice Further discussion and consideration required: - * - * - Consider changing the underscore in the internal methods to `unsafe` or - * adopting dot notation for prefixing imports. - * - Revise logic once contract-to-contract interactions are available on midnight. - * - Consider implementing an introspection mechanism for transfers to contracts. - * - Standardize which zero address to use (`ZswapCoinPublicKey` or `ContractAddress`). - */ -module ERC20 { - import CompactStandardLibrary; - import "../node_modules/@openzeppelin-midnight-contracts/utils-contract/dist/Utils" prefix Utils_; - - /// Public state - export ledger _name: Maybe>; - export ledger _symbol: Maybe>; - export ledger _decimals: Uint<8>; - export ledger _totalSupply: Uint<128>; - export ledger _balances: Map, Uint<128>>; - export ledger _allowances: Map, Map, Uint<128>>>; - - /** - * @description Initializes the contract by setting the name, symbol, and decimals. - * - * @param name_ - The name of the token. - * @param symbol_ - The symbol of the token. - * @param decimals_ - The number of decimals used to get the user representation. - */ - export circuit initializer( - name_: Maybe>, - symbol_: Maybe>, - decimals_:Uint<8> - ): [] { - _name = name_; - _symbol = symbol_; - _decimals = decimals_; - } - - /** - * @description Returns the token name. - * - * @return {Maybe>} - The token name. - */ - export circuit name(): Maybe> { - return _name; - } - - /** - * @description Returns the symbol of the token. - * - * @return {Maybe>} - The token name. - */ - export circuit symbol(): Maybe> { - return _symbol; - } - - /** - * @description Returns the number of decimals used to get its user representation. - * - * @return {Uint<8>} - The account's token balance. - */ - export circuit decimals(): Uint<8> { - return _decimals; - } - - /** - * @description Returns the value of tokens in existence. - * - * @return {Uint<128>} - The total supply of tokens. - */ - export circuit totalSupply(): Uint<128> { - return _totalSupply; - } - - /** - * @description Returns the value of tokens owned by `account`. - * - * @dev Manually checks if `account` is a key in the map and returns 0 if it is not. - * - * @param {account} - The public key or contract address to query. - * @return {Uint<128>} - The account's token balance. - */ - export circuit balanceOf(account: Either): Uint<128> { - if (!_balances.member(account)) { - return 0; - } - - return _balances.lookup(account); - } - - /** - * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` - * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. - * - * @dev Manually checks if `owner` and `spender` are keys in the map and returns 0 if they are not. - * - * @param {owner} - The public key or contract address of approver. - * @param {spender} - The public key or contract address of spender. - * @return {Uint<128>} - The `spender`'s allowance over `owner`'s tokens. - */ - export circuit allowance( - owner: Either, - spender: Either - ): Uint<128> { - if (!_allowances.member(owner) || !_allowances.lookup(owner).member(spender)) { - return 0; - } - - return _allowances.lookup(owner).lookup(spender); - } - - /** - * @description Moves a `value` amount of tokens from the caller's account to `to`. - * - * @dev We need to get the caller address from contracts and handle the transfer appropriately. - * This should include a callback to ensure the contract can safely receive tokens. - * - * @param {to} - The recipient of the transfer, either a user or a contract. - * @param {value} - The amount to transfer. - * @return {Boolean} - As per the IERC20 spec, this MUST return true. - */ - export circuit transfer(to: Either, value: Uint<128>): Boolean { - // TMP - Waiting for contract-to-contract calls to handle `right` with contract address - const owner = left(own_public_key()); - _transfer(owner, to, value); - return true; - } - - /** - * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. - * `value` is the deducted from the caller's allowance. - * - * @dev We need to get the caller address from contracts and handle the transfer appropriately. - * This should include a callback to ensure the contract can safely receive tokens. - * - * @param {from} - The current owner of the tokens for the transfer, either a user or a contract. - * @param {to} - The recipient of the transfer, either a user or a contract. - * @param {value} - The amount to transfer. - * @return {Boolean} - As per the IERC20 spec, this MUST return true. - */ - export circuit transferFrom( - from: Either, - to: Either, - value: Uint<128> - ): Boolean { - // TMP - Waiting for contract-to-contract calls to handle `right` with contract address - const spender = left(own_public_key()); - _spendAllowance(from, spender, value); - _transfer(from, to, value); - return true; - } - - /** - * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. - * - * @param {spender} - The Zswap key or ContractAddress that may spend on behalf of the caller. - * @param {value} - The amount of tokens the `spender` may spend. - * @return {Boolean} - Returns a boolean value indicating whether the operation succeeded. - */ - export circuit approve(spender: Either, value: Uint<128>): Boolean { - // TMP - Waiting for contract-to-contract calls to handle `right` with contract address - const owner = left(own_public_key()); - _approve(owner, spender, value); - return true; - } - - /** - * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. - * This internal function is equivalent to `approve`, and can be used to - * e.g. set automatic allowances for certain subsystems, etc. - * - * @param {owner} - The owner of the tokens. - * @param {spender} - The spender of the tokens. - * @param {value} - The amount of tokens `spender` may spend on behalf of `owner`. - * @return {[]} - None. - */ - export circuit _approve( - owner: Either, - spender: Either, - value: Uint<128> - ): [] { - assert !Utils_isZero(owner) "ERC20: invalid owner"; - assert !Utils_isZero(spender) "ERC20: invalid spender"; - if (!_allowances.member(owner)) { - // If owner doesn't exist, create and insert a new sub-map directly - _allowances.insert(owner, default, Uint<128>>>); - } - _allowances.lookup(owner).insert(spender, value); - } - - /** - * @description Moves a `value` amount of tokens from `from` to `to`. - * This internal function is equivalent to {transfer}, and can be used to - * e.g. implement automatic token fees, slashing mechanisms, etc. - * - * @param {from} - The owner of the tokens to transfer. - * @param {to} - The receipient of the transferred tokens. - * @param {value} - The amount of tokens to transfer. - * @return {[]} - None. - */ - export circuit _transfer( - from: Either, - to: Either, - value: Uint<128> - ): [] { - assert !Utils_isZero(from) "ERC20: invalid sender"; - assert !Utils_isZero(to) "ERC20: invalid receiver"; - - _update(from, to, value); - } - - /** - * @description Creates a `value` amount of tokens and assigns them to `account`, - * by transferring it from the zero address. Relies on the `update` mechanism. - * - * @param {account} - The recipient of tokens minted. - * @param {value} - The amount of tokens minted. - * @return {[]} - None. - */ - export circuit _mint( - account: Either, - value: Uint<128> - ): [] { - assert !Utils_isZero(account) "ERC20: invalid receiver"; - // Using the contract variant of 0 - // TODO: Look into if this matters - const zero_address = right(ContractAddress{ pad(32, "") }); - - _update(zero_address, account, value); - } - - /** - * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. - * Relies on the `_update` mechanism. - * - * @param {account} - The target owner of tokens to burn. - * @param {value} - The amount of tokens to burn. - * @return {[]} - None. - */ - export circuit _burn( - account: Either, - value: Uint<128> - ): [] { - assert !Utils_isZero(account) "ERC20: invalid sender"; - // Using the contract variant of 0 - // TODO: Look into if this matters - const zero_address = right(ContractAddress{ pad(32, "") }); - _update(account, zero_address, value); - } - - /** - * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` - * (or `to`) is the zero address. - * @dev Checks for a mint overflow in order to output a more readable error message. - * - * @param {from} - The original owner of the tokens moved (which is 0 if tokens are minted). - * @param {to} - The recipient of the tokens moved (which is 0 if tokens are burned). - * @param {value} - The amount of tokens moved from `from` to `to`. - * @return {[]} - None. - */ - export circuit _update( - from: Either, - to: Either, - value: Uint<128> - ): [] { - if (Utils_isZero(from)) { - // Mint - const MAX_UINT128 = 340282366920938463463374607431768211455; - assert MAX_UINT128 - _totalSupply >= value "ERC20: arithmetic overflow"; - - _totalSupply = _totalSupply + value as Uint<128>; - } else { - const fromBal = balanceOf(from); - assert fromBal >= value "ERC20: insufficient balance"; - _balances.insert(from, fromBal - value as Uint<128>); - } - - if (Utils_isZero(to)) { - // Burn - _totalSupply = _totalSupply - value as Uint<128>; - } else { - const toBal = balanceOf(to); - _balances.insert(to, toBal + value as Uint<128>); - } - } - - /** - * @description Updates `owner`'s allowance for `spender` based on spent `value`. - * Does not update the allowance value in case of infinite allowance. - * - * @param {owner} - The owner of the tokens. - * @param {spender} - The spender of the tokens. - * @param {value} - The amount of token allowance to spend. - * @return {[]} - None. - */ - export circuit _spendAllowance( - owner: Either, - spender: Either, - value: Uint<128> - ): [] { - // TODO: Look into improving design so we're not checking allowance member twice (here and in `_approve`) - assert (_allowances.member(owner) && _allowances.lookup(owner).member(spender)) "ERC20: insufficient allowance"; - - const currentAllowance = _allowances.lookup(owner).lookup(spender); - // TODO: improve readability of max_u128 - const MAX_UINT128 = 340282366920938463463374607431768211455; - if (currentAllowance < MAX_UINT128) { - assert currentAllowance >= value "ERC20: insufficient allowance"; - _approve(owner, spender, currentAllowance - value as Uint<128>); - } - } -} diff --git a/contracts/erc20/contract/src/MockERC20.compact b/contracts/erc20/contract/src/MockERC20.compact deleted file mode 100644 index c9d53c38..00000000 --- a/contracts/erc20/contract/src/MockERC20.compact +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.14.0; - -import CompactStandardLibrary; - -import ERC20 prefix ERC20_; - -export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; - -constructor( - _name: Maybe>, - _symbol: Maybe>, - _decimals:Uint<8> -) { - ERC20_initializer(_name, _symbol, _decimals); -} - -export circuit name(): Maybe> { - return ERC20_name(); -} - -export circuit symbol(): Maybe> { - return ERC20_symbol(); -} - -export circuit decimals(): Uint<8> { - return ERC20_decimals(); -} - -export circuit totalSupply(): Uint<128> { - return ERC20_totalSupply(); -} - -export circuit balanceOf(account: Either): Uint<128> { - return ERC20_balanceOf(account); -} - -export circuit allowance( - owner: Either, - spender: Either -): Uint<128> { - return ERC20_allowance(owner, spender); -} - -export circuit transfer(to: Either, value: Uint<128>): Boolean { - return ERC20_transfer(to, value); -} - -export circuit transferFrom( - from: Either, - to: Either, - value: Uint<128> -): Boolean { - return ERC20_transferFrom(from, to, value); -} - -export circuit approve(spender: Either, value: Uint<128>): Boolean { - return ERC20_approve(spender, value); -} - -export circuit _approve( - owner: Either, - spender: Either, - value: Uint<128> -): [] { - return ERC20__approve(owner, spender, value); -} - -export circuit _transfer( - from: Either, - to: Either, - value: Uint<128> -): [] { - return ERC20__transfer(from, to, value); -} - -export circuit _mint( - account: Either, - value: Uint<128> -): [] { - return ERC20__mint(account, value); -} - -export circuit _burn( - account: Either, - value: Uint<128> -): [] { - return ERC20__burn(account, value); -} - -export circuit _update( - from: Either, - to: Either, - value: Uint<128> -): [] { - return ERC20__update(from, to, value); -} - -export circuit _spendAllowance( - owner: Either, - spender: Either, - value: Uint<128> -): [] { - return ERC20__spendAllowance(owner, spender, value); -} - -export pure circuit isZero(keyOrAddress: Either): Boolean { - return ERC20_isZero(keyOrAddress); -} diff --git a/contracts/erc20/contract/src/test/ERC20Simulator.ts b/contracts/erc20/contract/src/test/ERC20Simulator.ts deleted file mode 100644 index c1cb2cba..00000000 --- a/contracts/erc20/contract/src/test/ERC20Simulator.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { - type CircuitContext, - CoinPublicKey, - type ContractState, - QueryContext, - constructorContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; -import { - type Ledger, - Contract as MockERC20, - ledger, - Either, - ZswapCoinPublicKey, - ContractAddress, -} from './../artifacts/MockERC20/contract/index.cjs'; // Combined imports -import { MaybeString } from './types.js'; -import type { IContractSimulator } from './../types'; -import { ERC20PrivateState, ERC20Witnesses } from './../witnesses'; - -/** - * @description A simulator implementation of an erc20 contract for testing purposes. - * @template P - The private state type, fixed to ERC20PrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. - */ -export class ERC20ContractSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockERC20; - - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor(name: MaybeString, symbol: MaybeString, decimals: bigint) { - this.contract = new MockERC20( - ERC20Witnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)), name, symbol, decimals, - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type ERC20PrivateState. - */ - public getCurrentPrivateState(): ERC20PrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; - } - - /** - * @description Returns the token name. - * @returns The token name. - */ - public name(): MaybeString { - return this.contract.impureCircuits.name(this.circuitContext).result; - } - - /** - * @description Returns the symbol of the token. - * @returns The token name. - */ - public symbol(): MaybeString { - return this.contract.impureCircuits.symbol(this.circuitContext).result; - } - - /** - * @description Returns the number of decimals used to get its user representation. - * @returns The account's token balance. - */ - public decimals(): bigint { - return this.contract.impureCircuits.decimals(this.circuitContext).result; - } - - /** - * @description Returns the value of tokens in existence. - * @returns The total supply of tokens. - */ - public totalSupply(): bigint { - return this.contract.impureCircuits.totalSupply(this.circuitContext).result; - } - - /** - * @description Returns the value of tokens owned by `account`. - * @param account The public key or contract address to query. - * @returns The account's token balance. - */ - public balanceOf(account: Either): bigint { - return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; - } - - /** - * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` - * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. - * @param owner The public key or contract address of approver. - * @param spender The public key or contract address of spender. - * @returns The `spender`'s allowance over `owner`'s tokens. - */ - public allowance( - owner: Either, - spender: Either - ): bigint { - return this.contract.impureCircuits.allowance(this.circuitContext, owner, spender).result; - } - - /** - * @description Moves a `value` amount of tokens from the caller's account to `to`. - * @param to The recipient of the transfer, either a user or a contract. - * @param value The amount to transfer. - * @param sender The simulated caller. - * @returns As per the IERC20 spec, this MUST return true. - */ - public transfer(to: Either, value: bigint, sender?: CoinPublicKey): boolean { - const res = this.contract.impureCircuits.transfer({ - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, to, value - ); - - this.circuitContext = res.context; - return res.result; - } - - /** - * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. - * `value` is the deducted from the caller's allowance. - * @param from The current owner of the tokens for the transfer, either a user or a contract. - * @param to The recipient of the transfer, either a user or a contract. - * @param value The amount to transfer. - * @param sender The simulated caller. - * @returns As per the IERC20 spec, this MUST return true. - */ - public transferFrom( - from: Either, - to: Either, - value: bigint, - sender?: CoinPublicKey - ): boolean { - const res = this.contract.impureCircuits.transferFrom({ - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, to, value - ); - - this.circuitContext = res.context; - return res.result; - } - - /** - * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. - * @param spender The Zswap key or ContractAddress that may spend on behalf of the caller. - * @param value The amount of tokens the `spender` may spend. - * @param sender The simulated caller. - * @returns Returns a boolean value indicating whether the operation succeeded. - */ - public approve(spender: Either, value: bigint, sender?: CoinPublicKey): boolean { - const res = this.contract.impureCircuits.approve({ - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - spender, value - ); - - this.circuitContext = res.context; - return res.result; - } - - /// - /// Internal - /// - - /** - * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. - * This internal function is equivalent to `approve`, and can be used to - * e.g. set automatic allowances for certain subsystems, etc. - * @param owner The owner of the tokens. - * @param spender The spender of the tokens. - * @param value The amount of tokens `spender` may spend on behalf of `owner`. - * @returns None. - */ - public _approve( - owner: Either, - spender: Either, - value: bigint - ) { - this.circuitContext = this.contract.impureCircuits._approve(this.circuitContext, owner, spender, value).context; - } - - /** - * @description Moves a `value` amount of tokens from `from` to `to`. - * This internal function is equivalent to {transfer}, and can be used to - * e.g. implement automatic token fees, slashing mechanisms, etc. - * @param from The owner of the tokens to transfer. - * @param to The receipient of the transferred tokens. - * @param value The amount of tokens to transfer. - */ - public _transfer( - from: Either, - to: Either, - value: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._transfer(this.circuitContext, from, to, value).context; - } - - /** - * @description Creates a `value` amount of tokens and assigns them to `account`, - * by transferring it from the zero address. Relies on the `update` mechanism. - * @param account The recipient of tokens minted. - * @param value The amount of tokens minted. - */ - public _mint(account: Either, value: bigint) { - this.circuitContext = this.contract.impureCircuits._mint(this.circuitContext, account, value).context; - } - - /** - * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. - * Relies on the `_update` mechanism. - * @param account The target owner of tokens to burn. - * @param value The amount of tokens to burn. - */ - public _burn(account: Either, value: bigint) { - this.circuitContext = this.contract.impureCircuits._burn(this.circuitContext, account, value).context; - } - - /** - * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` - * (or `to`) is the zero address. - * @param from The original owner of the tokens moved (which is 0 if tokens are minted). - * @param to The recipient of the tokens moved (which is 0 if tokens are burned). - * @param value The amount of tokens moved from `from` to `to`. - */ - public _update( - from: Either, - to: Either, - value: bigint - ) { - this.circuitContext = this.contract.impureCircuits._update(this.circuitContext, from, to, value).context; - } - - /** - * @description Updates `owner`'s allowance for `spender` based on spent `value`. - * Does not update the allowance value in case of infinite allowance. - * @param owner The owner of the tokens. - * @param spender The spender of the tokens. - * @param value The amount of token allowance to spend. - */ - public _spendAllowance( - owner: Either, - spender: Either, - value: bigint - ) { - this.circuitContext = this.contract.impureCircuits._spendAllowance(this.circuitContext, owner, spender, value).context; - } - - /** - * @description Returns whether `keyOrAddress` is the zero address. - * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. - * @returns Returns true if `keyOrAddress` is zero. - */ - public isZero(keyOrAddress: Either): boolean { - return this.contract.circuits.isZero(this.circuitContext, keyOrAddress).result; - } -} diff --git a/contracts/erc20/contract/src/test/erc20.test.ts b/contracts/erc20/contract/src/test/erc20.test.ts deleted file mode 100644 index 628ecd0d..00000000 --- a/contracts/erc20/contract/src/test/erc20.test.ts +++ /dev/null @@ -1,485 +0,0 @@ -import { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; -import { ERC20ContractSimulator } from './ERC20Simulator'; -import { MaybeString } from './types.js'; -import * as utils from './utils.js'; -import { after } from 'node:test'; - -const NO_STRING: MaybeString = { - is_some: false, - value: '' -}; -const NAME: MaybeString = { - is_some: true, - value: "NAME" -}; -const SYMBOL: MaybeString = { - is_some: true, - value: "SYMBOL" -}; -const DECIMALS: bigint = 18n; - -const AMOUNT: bigint = BigInt(250); -const MAX_UINT128 = BigInt(2**128) - BigInt(1); - -const OWNER = String(Buffer.from("OWNER", 'ascii').toString('hex')).padStart(64, '0'); -const SPENDER = String(Buffer.from("SPENDER", 'ascii').toString('hex')).padStart(64, '0'); -const UNAUTHORIZED = String(Buffer.from("UNAUTHORIZED", 'ascii').toString('hex')).padStart(64, '0'); -const ZERO = String().padStart(64, '0'); -const Z_OWNER = utils.createEitherTestUser('OWNER'); -const Z_RECIPIENT = utils.createEitherTestUser('RECIPIENT'); -const Z_SPENDER = utils.createEitherTestUser('SPENDER'); -const Z_OTHER = utils.createEitherTestUser('OTHER'); -const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); - -let token: ERC20ContractSimulator; -let caller: CoinPublicKey; - -describe('ERC20', () => { - describe('initializer and metadata', () => { - it('should initialize metadata', () => { - token = new ERC20ContractSimulator(NAME, SYMBOL, DECIMALS); - - expect(token.name()).toEqual(NAME); - expect(token.symbol()).toEqual(SYMBOL); - expect(token.decimals()).toEqual(DECIMALS); - }); - - it('should initialize empty metadata', () => { - const NO_DECIMALS = 0n; - token = new ERC20ContractSimulator(NO_STRING, NO_STRING, NO_DECIMALS); - - expect(token.name()).toEqual(NO_STRING); - expect(token.symbol()).toEqual(NO_STRING); - expect(token.decimals()).toEqual(NO_DECIMALS); - }); - }); - - beforeEach(() => { - token = new ERC20ContractSimulator(NAME, SYMBOL, DECIMALS); - }); - - describe('totalSupply', () => { - it('returns 0 when there is no supply', () => { - expect(token.totalSupply()).toEqual(0n); - }); - - it('returns the amount of existing tokens when there is a supply', () => { - token._mint(Z_OWNER, AMOUNT); - expect(token.totalSupply()).toEqual(AMOUNT); - }) - }) - - describe('balanceOf', () => { - it('should return zero when requested account has no balance', () => { - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - - it('should return balance when requested account has tokens', () => { - token._mint(Z_OWNER, AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); - }); - - describe('transfer', () => { - beforeEach(() => { - token._mint(Z_OWNER, AMOUNT); - - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); - }); - - afterEach(() => { - expect(token.totalSupply()).toEqual(AMOUNT); - //expect(token.getCurrentPublicState().eRC20_TotalSupply).toEqual(AMOUNT); - }); - - it('should transfer partial', () => { - const partialAmt = AMOUNT - 1n; - caller = OWNER; - const txSuccess = token.transfer(Z_RECIPIENT, partialAmt, caller); - - expect(txSuccess).toBeTruthy(); - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); - }); - - it('should transfer full', () => { - caller = OWNER; - const txSuccess = token.transfer(Z_RECIPIENT, AMOUNT, caller); - - expect(txSuccess).toBeTruthy(); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); - }); - - it('should fail with insufficient balance', () => { - caller = OWNER; - - expect(() => { - token.transfer(Z_RECIPIENT, AMOUNT + 1n, caller); - }).toThrow('ERC20: insufficient balance'); - }); - - it('should fail with transfer from zero', () => { - caller = ZERO; - - expect(() => { - token.transfer(Z_RECIPIENT, AMOUNT, caller); - }).toThrow('ERC20: invalid sender'); - }); - - it('should fail with transfer to zero', () => { - caller = OWNER; - - expect(() => { - token.transfer(utils.ZERO_ADDRESS, AMOUNT, caller); - }).toThrow('ERC20: invalid receiver'); - }); - - it('should allow transfer of 0 tokens', () => { - const txSuccess = token.transfer(Z_RECIPIENT, 0n, caller); - - expect(txSuccess).toBeTruthy(); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); - }); - - it('should handle transfer with empty _balances', () => { - caller = SPENDER; - - expect(() => { - token.transfer(Z_RECIPIENT, 1n, caller); - }).toThrow('ERC20: insufficient balance'); - }); - }); - - describe('approve', () => { - beforeEach(() => { - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - }); - - it('should approve and update allowance', () => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); - }); - - it('should approve and update allowance for multiple spenders', () => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); - - token.approve(Z_OTHER, AMOUNT, caller); - expect(token.allowance(Z_OWNER, Z_OTHER)).toEqual(AMOUNT); - - expect(token.allowance(Z_OWNER, Z_RECIPIENT)).toEqual(0n); - }); - - it('should fail when approve from zero', () => { - caller = ZERO; - - expect(() => { - token.approve(Z_SPENDER, AMOUNT, caller); - }).toThrow('ERC20: invalid owner'); - }); - - it('should fail when approve to zero', () => { - caller = OWNER; - - expect(() => { - token.approve(utils.ZERO_ADDRESS, AMOUNT, caller); - }).toThrow('ERC20: invalid spender'); - }); - - it('should transfer exact allowance and fail subsequent transfer', () => { - token._mint(Z_OWNER, AMOUNT); - caller = OWNER; - token.approve(Z_SPENDER, AMOUNT, caller); - - caller = SPENDER; - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, 1n, caller); - }).toThrow('ERC20: insufficient allowance'); - }); - - it('should allow approve of 0 tokens', () => { - caller = OWNER; - token.approve(Z_SPENDER, 0n, caller); - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - }); - - it('should handle allowance with empty _allowances', () => { - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - }); - }); - - describe('transferFrom', () => { - beforeEach(() => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); - token._mint(Z_OWNER, AMOUNT); - }); - - afterEach(() => { - expect(token.totalSupply()).toEqual(AMOUNT); - }); - - it('should transferFrom spender (partial)', () => { - caller = SPENDER; - const partialAmt = AMOUNT - 1n; - - const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, partialAmt, caller); - expect(txSuccess).toBeTruthy(); - - // Check balances - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); - // Check leftover allowance - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(1n); - }); - - it('should transferFrom spender (full)', () => { - caller = SPENDER; - - const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - expect(txSuccess).toBeTruthy(); - - // Check balances - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); - // Check no allowance - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - }); - - it('should transferFrom and not consume infinite allowance', () => { - caller = OWNER; - token.approve(Z_SPENDER, MAX_UINT128, caller); - - caller = SPENDER; - const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - expect(txSuccess).toBeTruthy(); - - // Check balances - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); - // Check infinite allowance - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(MAX_UINT128); - }); - - it ('should fail when transfer amount exceeds allowance', () => { - caller = SPENDER; - - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n); - }).toThrow('ERC20: insufficient allowance'); - }); - - it ('should fail when transfer amount exceeds balance', () => { - caller = OWNER; - // Increase allowance > balance - token.approve(Z_SPENDER, AMOUNT + 1n, caller); - - caller = SPENDER; - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n, caller); - }).toThrow('ERC20: insufficient balance'); - }); - - it('should fail when spender does not have allowance', () => { - caller = UNAUTHORIZED; - - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - }).toThrow("ERC20: insufficient allowance"); - }); - - it('should fail to transferFrom zero address', () => { - caller = ZERO; - - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - }).toThrow("ERC20: insufficient allowance"); - }); - - it('should fail to transferFrom to the zero address', () => { - caller = SPENDER; - - expect(() => { - token.transferFrom(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT, caller); - }).toThrow("ERC20: invalid receiver"); - }); - }); - - describe('_transfer', () => { - beforeEach(() => { - token._mint(Z_OWNER, AMOUNT); - }); - - afterEach(() => { - expect(token.totalSupply()).toEqual(AMOUNT); - }); - - it('should update balances (partial)', () => { - const partialAmt = AMOUNT - 1n; - token._transfer(Z_OWNER, Z_RECIPIENT, partialAmt); - - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); - }); - }) - - describe('_mint', () => { - it('should mint and update supply', () => { - expect(token.totalSupply()).toEqual(0n); - - token._mint(Z_RECIPIENT, AMOUNT); - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); - }); - - it('should catch mint overflow', () => { - token._mint(Z_RECIPIENT, MAX_UINT128); - - expect(() => { - token._mint(Z_RECIPIENT, 1n); - }).toThrow('ERC20: arithmetic overflow'); - }); - - it('should not mint to zero pubkey', () => { - expect(() => { - token._mint(utils.ZERO_KEY, AMOUNT); - }).toThrow('ERC20: invalid receiver'); - }); - - it('should not mint to zero contract address', () => { - expect(() => { - token._mint(utils.ZERO_ADDRESS, AMOUNT); - }).toThrow('ERC20: invalid receiver'); - }); - - it('should allow mint of 0 tokens', () => { - token._mint(Z_OWNER, 0n); - expect(token.totalSupply()).toEqual(0n); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - }); - - describe('_burn', () => { - beforeEach(() => { - token._mint(Z_OWNER, AMOUNT); - }); - - it('should burn tokens', () => { - token._burn(Z_OWNER, 1n); - - const afterBurn = AMOUNT - 1n; - expect(token.balanceOf(Z_OWNER)).toEqual(afterBurn); - expect(token.totalSupply()).toEqual(afterBurn); - }); - - it('should throw when burning from zero', () => { - expect(() => { - token._burn(utils.ZERO_KEY, AMOUNT); - }).toThrow('ERC20: invalid sender'); - }); - - it('should throw when burn amount is greater than balance', () => { - expect(() => { - token._burn(Z_OWNER, AMOUNT + 1n); - }).toThrow('ERC20: insufficient balance'); - }); - - it('should allow burn of 0 tokens', () => { - token._burn(Z_OWNER, 0n); - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); - }); - - describe('_update', () => { - it('should update from zero to non-zero (mint)', () => { - expect(token.totalSupply()).toEqual(0n); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - - token._update(utils.ZERO_KEY, Z_OWNER, AMOUNT); - - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); - - it('should catch overflow from zero to non-zero (mint)', () => { - token._update(utils.ZERO_KEY, Z_OWNER, MAX_UINT128); - - expect(() => { - token._update(utils.ZERO_KEY, Z_OWNER, 1n); - }).toThrow('ERC20: arithmetic overflow'); - }); - - describe('with minted tokens', () => { - beforeEach(() => { - token._update(utils.ZERO_ADDRESS, Z_OWNER, AMOUNT); - - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); - - it('should update from non-zero to zero (burn)', () => { - token._update(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); - - expect(token.totalSupply()).toEqual(0n); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - - it('should catch overflow from non-zero to zero (burn)', () => { - token._update(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); - - expect(() => { - token._update(Z_OWNER, utils.ZERO_ADDRESS, 1n); - }).toThrow('ERC20: insufficient balance'); - }); - - it('should update from non-zero to non-zero (transfer)', () => { - token._update(Z_OWNER, Z_RECIPIENT, AMOUNT - 1n); - - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); - }); - }); - }); - - describe('isZero', () => { - it('should return zero for the zero address', () => { - expect(token.isZero(utils.ZERO_KEY)).toBeTruthy(); - expect(token.isZero(utils.ZERO_ADDRESS)).toBeTruthy(); - }); - - it('should not return zero for nonzero addresses', () => { - expect(token.isZero(Z_OWNER)).toBeFalsy(); - expect(token.isZero(SOME_CONTRACT)).toBeFalsy(); - }); - }); - - describe('Multiple Operations', () => { - it('should handle mint → transfer → burn sequence', () => { - token._mint(Z_OWNER, AMOUNT); - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - - caller = OWNER; - token.transfer(Z_RECIPIENT, AMOUNT - 1n, caller); - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); - - token._burn(Z_OWNER, 1n); - expect(token.totalSupply()).toEqual(AMOUNT - 1n); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - }); -}); diff --git a/contracts/erc20/contract/src/types/index.ts b/contracts/erc20/contract/src/types/index.ts deleted file mode 100644 index db642b5e..00000000 --- a/contracts/erc20/contract/src/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { IContractSimulator } from './test'; diff --git a/contracts/erc20/contract/src/utils/index.ts b/contracts/erc20/contract/src/utils/index.ts deleted file mode 100644 index 14e02ef2..00000000 --- a/contracts/erc20/contract/src/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { useCircuitContext as circuitContext } from './test'; diff --git a/contracts/erc20/contract/src/witnesses/ERC20Witnesses.ts b/contracts/erc20/contract/src/witnesses/ERC20Witnesses.ts deleted file mode 100644 index 22caf6cf..00000000 --- a/contracts/erc20/contract/src/witnesses/ERC20Witnesses.ts +++ /dev/null @@ -1,7 +0,0 @@ -// This is how we type an empty object. -export type ERC20PrivateState = Record; - -export const witnesses = {}; -export const ERC20Witnesses = {}; - -export const createERC20PrivateState = () => ({}); diff --git a/contracts/erc20/contract/src/witnesses/index.ts b/contracts/erc20/contract/src/witnesses/index.ts deleted file mode 100644 index dc29bf8e..00000000 --- a/contracts/erc20/contract/src/witnesses/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../artifacts/erc20/contract/index.cjs'; -export * from './ERC20Witnesses.js'; diff --git a/contracts/erc20/contract/.eslintignore b/contracts/utils/.eslintignore similarity index 100% rename from contracts/erc20/contract/.eslintignore rename to contracts/utils/.eslintignore diff --git a/contracts/erc20/contract/.eslintrc.cjs b/contracts/utils/.eslintrc.cjs similarity index 100% rename from contracts/erc20/contract/.eslintrc.cjs rename to contracts/utils/.eslintrc.cjs diff --git a/contracts/utils/contract/.eslintignore b/contracts/utils/contract/.eslintignore deleted file mode 100644 index 652df825..00000000 --- a/contracts/utils/contract/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -src/managed diff --git a/contracts/utils/contract/.eslintrc.cjs b/contracts/utils/contract/.eslintrc.cjs deleted file mode 100644 index 581f1d49..00000000 --- a/contracts/utils/contract/.eslintrc.cjs +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - node: true, - jest: true, - }, - extends: [ - 'standard-with-typescript', - 'plugin:prettier/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - overrides: [], - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['tsconfig.json'], - }, - rules: { - '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 - '@typescript-eslint/no-floating-promises': 'warn', - '@typescript-eslint/promise-function-async': 'off', - '@typescript-eslint/no-redeclare': 'off', - '@typescript-eslint/no-invalid-void-type': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/consistent-type-definitions': 'off' - }, -}; diff --git a/contracts/utils/contract/jest.config.ts b/contracts/utils/contract/jest.config.ts deleted file mode 100644 index edbdaeba..00000000 --- a/contracts/utils/contract/jest.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Config } from "@jest/types"; - -const config: Config.InitialOptions = { - preset: "ts-jest/presets/default-esm", - testEnvironment: "node", - verbose: true, - roots: [""], - modulePaths: [""], - passWithNoTests: false, - testMatch: ["**/*.test.ts"], - extensionsToTreatAsEsm: [".ts"], - collectCoverage: true, - resolver: '/js-resolver.cjs', - coverageThreshold: { - global: { - //branches: 60, - //functions: 75, - //lines: 70, - }, - }, - reporters: [ - "default", - ["jest-junit", { outputDirectory: "reports", outputName: "report.xml" }], - ["jest-html-reporters", { publicPath: "reports", filename: "report.html" }], - ], -}; - -export default config; diff --git a/contracts/utils/contract/js-resolver.cjs b/contracts/utils/contract/js-resolver.cjs deleted file mode 100644 index cc9ed285..00000000 --- a/contracts/utils/contract/js-resolver.cjs +++ /dev/null @@ -1,16 +0,0 @@ -const jsResolver = (path, options) => { - const jsExtRegex = /\.js$/i - const resolver = options.defaultResolver - if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { - const newPath = path.replace(jsExtRegex, '.ts'); - try { - return resolver(newPath, options) - } catch { - // use default resolver - } - } - - return resolver(path, options) -} - -module.exports = jsResolver diff --git a/contracts/utils/contract/src/test/UtilsSimulator.ts b/contracts/utils/contract/src/test/UtilsSimulator.ts deleted file mode 100644 index 34995957..00000000 --- a/contracts/utils/contract/src/test/UtilsSimulator.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { - type CircuitContext, - CoinPublicKey, - type ContractState, - QueryContext, - constructorContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; -import { - type Ledger, - Contract as MockUtils, - ledger, - Either, - ZswapCoinPublicKey, - ContractAddress, -} from '../artifacts/MockUtils/contract/index.cjs'; // Combined imports -import { MaybeString } from './types.js'; -import type { IContractSimulator } from '../types/index.js'; -import { UtilsPrivateState, UtilsWitnesses } from '../witnesses/index.js'; - -/** - * @description A simulator implementation of an utils contract for testing purposes. - * @template P - The private state type, fixed to UtilsPrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. - */ -export class UtilsContractSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockUtils; - - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor() { - this.contract = new MockUtils( - UtilsWitnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)) - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type UtilsPrivateState. - */ - public getCurrentPrivateState(): UtilsPrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; - } - -// /** -// * @description Returns the token name. -// * @returns The token name. -// */ -// public name(): MaybeString { -// return this.contract.impureCircuits.name(this.circuitContext).result; -// } -// -// /** -// * @description Returns the symbol of the token. -// * @returns The token name. -// */ -// public symbol(): MaybeString { -// return this.contract.impureCircuits.symbol(this.circuitContext).result; -// } -// -// /** -// * @description Returns the number of decimals used to get its user representation. -// * @returns The account's token balance. -// */ -// public decimals(): bigint { -// return this.contract.impureCircuits.decimals(this.circuitContext).result; -// } -// -// /** -// * @description Returns the value of tokens in existence. -// * @returns The total supply of tokens. -// */ -// public totalSupply(): bigint { -// return this.contract.impureCircuits.totalSupply(this.circuitContext).result; -// } -// -// /** -// * @description Returns the value of tokens owned by `account`. -// * @param account The public key or contract address to query. -// * @returns The account's token balance. -// */ -// public balanceOf(account: Either): bigint { -// return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; -// } -// -// /** -// * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` -// * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. -// * @param owner The public key or contract address of approver. -// * @param spender The public key or contract address of spender. -// * @returns The `spender`'s allowance over `owner`'s tokens. -// */ -// public allowance( -// owner: Either, -// spender: Either -// ): bigint { -// return this.contract.impureCircuits.allowance(this.circuitContext, owner, spender).result; -// } -// -// /** -// * @description Moves a `value` amount of tokens from the caller's account to `to`. -// * @param to The recipient of the transfer, either a user or a contract. -// * @param value The amount to transfer. -// * @param sender The simulated caller. -// * @returns As per the IUtils spec, this MUST return true. -// */ -// public transfer(to: Either, value: bigint, sender?: CoinPublicKey): boolean { -// const res = this.contract.impureCircuits.transfer({ -// ...this.circuitContext, -// currentZswapLocalState: sender -// ? emptyZswapLocalState(sender) -// : this.circuitContext.currentZswapLocalState, -// }, to, value -// ); -// -// this.circuitContext = res.context; -// return res.result; -// } -// -// /** -// * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. -// * `value` is the deducted from the caller's allowance. -// * @param from The current owner of the tokens for the transfer, either a user or a contract. -// * @param to The recipient of the transfer, either a user or a contract. -// * @param value The amount to transfer. -// * @param sender The simulated caller. -// * @returns As per the IUtils spec, this MUST return true. -// */ -// public transferFrom( -// from: Either, -// to: Either, -// value: bigint, -// sender?: CoinPublicKey -// ): boolean { -// const res = this.contract.impureCircuits.transferFrom({ -// ...this.circuitContext, -// currentZswapLocalState: sender -// ? emptyZswapLocalState(sender) -// : this.circuitContext.currentZswapLocalState, -// }, -// from, to, value -// ); -// -// this.circuitContext = res.context; -// return res.result; -// } -// -// /** -// * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. -// * @param spender The Zswap key or ContractAddress that may spend on behalf of the caller. -// * @param value The amount of tokens the `spender` may spend. -// * @param sender The simulated caller. -// * @returns Returns a boolean value indicating whether the operation succeeded. -// */ -// public approve(spender: Either, value: bigint, sender?: CoinPublicKey): boolean { -// const res = this.contract.impureCircuits.approve({ -// ...this.circuitContext, -// currentZswapLocalState: sender -// ? emptyZswapLocalState(sender) -// : this.circuitContext.currentZswapLocalState, -// }, -// spender, value -// ); -// -// this.circuitContext = res.context; -// return res.result; -// } -// -// /// -// /// Internal -// /// -// -// /** -// * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. -// * This internal function is equivalent to `approve`, and can be used to -// * e.g. set automatic allowances for certain subsystems, etc. -// * @param owner The owner of the tokens. -// * @param spender The spender of the tokens. -// * @param value The amount of tokens `spender` may spend on behalf of `owner`. -// * @returns None. -// */ -// public _approve( -// owner: Either, -// spender: Either, -// value: bigint -// ) { -// this.circuitContext = this.contract.impureCircuits._approve(this.circuitContext, owner, spender, value).context; -// } -// -// /** -// * @description Moves a `value` amount of tokens from `from` to `to`. -// * This internal function is equivalent to {transfer}, and can be used to -// * e.g. implement automatic token fees, slashing mechanisms, etc. -// * @param from The owner of the tokens to transfer. -// * @param to The receipient of the transferred tokens. -// * @param value The amount of tokens to transfer. -// */ -// public _transfer( -// from: Either, -// to: Either, -// value: bigint, -// ) { -// this.circuitContext = this.contract.impureCircuits._transfer(this.circuitContext, from, to, value).context; -// } -// -// /** -// * @description Creates a `value` amount of tokens and assigns them to `account`, -// * by transferring it from the zero address. Relies on the `update` mechanism. -// * @param account The recipient of tokens minted. -// * @param value The amount of tokens minted. -// */ -// public _mint(account: Either, value: bigint) { -// this.circuitContext = this.contract.impureCircuits._mint(this.circuitContext, account, value).context; -// } -// -// /** -// * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. -// * Relies on the `_update` mechanism. -// * @param account The target owner of tokens to burn. -// * @param value The amount of tokens to burn. -// */ -// public _burn(account: Either, value: bigint) { -// this.circuitContext = this.contract.impureCircuits._burn(this.circuitContext, account, value).context; -// } -// -// /** -// * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` -// * (or `to`) is the zero address. -// * @param from The original owner of the tokens moved (which is 0 if tokens are minted). -// * @param to The recipient of the tokens moved (which is 0 if tokens are burned). -// * @param value The amount of tokens moved from `from` to `to`. -// */ -// public _update( -// from: Either, -// to: Either, -// value: bigint -// ) { -// this.circuitContext = this.contract.impureCircuits._update(this.circuitContext, from, to, value).context; -// } -// -// /** -// * @description Updates `owner`'s allowance for `spender` based on spent `value`. -// * Does not update the allowance value in case of infinite allowance. -// * @param owner The owner of the tokens. -// * @param spender The spender of the tokens. -// * @param value The amount of token allowance to spend. -// */ -// public _spendAllowance( -// owner: Either, -// spender: Either, -// value: bigint -// ) { -// this.circuitContext = this.contract.impureCircuits._spendAllowance(this.circuitContext, owner, spender, value).context; -// } -// - /** - * @description Returns whether `keyOrAddress` is the zero address. - * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. - * @returns Returns true if `keyOrAddress` is zero. - */ - public isZero(keyOrAddress: Either): boolean { - return this.contract.circuits.isZero(this.circuitContext, keyOrAddress).result; - } -} diff --git a/contracts/utils/contract/src/test/types.ts b/contracts/utils/contract/src/test/types.ts deleted file mode 100644 index 4735fab2..00000000 --- a/contracts/utils/contract/src/test/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type MaybeString = { - is_some: boolean, - value: string -} diff --git a/contracts/utils/contract/src/test/utils.ts b/contracts/utils/contract/src/test/utils.ts deleted file mode 100644 index e360bda1..00000000 --- a/contracts/utils/contract/src/test/utils.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import * as Compact from '../artifacts/MockUtils/contract/index.cjs'; -import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; - -const PREFIX_ADDRESS = "0200"; - -export const pad = (s: string, n: number): Uint8Array => { - const encoder = new TextEncoder(); - const utf8Bytes = encoder.encode(s); - if (n < utf8Bytes.length) { - throw new Error(`The padded length n must be at least ${utf8Bytes.length}`); - } - const paddedArray = new Uint8Array(n); - paddedArray.set(utf8Bytes); - return paddedArray; -} - -/** - * @description Generates ZswapCoinPublicKey from `str` for testing purposes. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; -} - -/** - * @description Generates ContractAddress from `str` for testing purposes. - * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToAddress = (str: string): Compact.ContractAddress => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); - return { bytes: encodeContractAddress(fullAddress) }; -} - -/** - * @description Generates an Either object for ZswapCoinPublicKey for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ZswapCoinPublicKey. - */ -export const createEitherTestUser = (str: string) => { - return { - is_left: true, - left: encodeToPK(str), - right: encodeToAddress('') - } -} - -/** - * @description Generates an Either object for ContractAddress for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ContractAddress. - */ -export const createEitherTestContractAddress = (str: string) => { - return { - is_left: false, - left: encodeToPK(''), - right: encodeToAddress(str) - } -} - -export const ZERO_KEY = { - is_left: true, - left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, - right: encodeToAddress('') -} - -export const ZERO_ADDRESS = { - is_left: false, - left: encodeToPK(''), - right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) } -} diff --git a/contracts/utils/contract/src/types/index.ts b/contracts/utils/contract/src/types/index.ts deleted file mode 100644 index db642b5e..00000000 --- a/contracts/utils/contract/src/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { IContractSimulator } from './test'; diff --git a/contracts/utils/contract/src/types/test.ts b/contracts/utils/contract/src/types/test.ts deleted file mode 100644 index 10fb6c98..00000000 --- a/contracts/utils/contract/src/types/test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; - -/** - * Generic interface for mock contract implementations. - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - */ -export interface IContractSimulator { - /** The contract's deployed address. */ - readonly contractAddress: string; - - /** The current circuit context. */ - circuitContext: CircuitContext

; - - /** Retrieves the current ledger state. */ - getCurrentPublicState(): L; - - /** Retrieves the current private state. */ - getCurrentPrivateState(): P; - - /** Retrieves the current contract state. */ - getCurrentContractState(): ContractState; -} diff --git a/contracts/utils/contract/src/utils/index.ts b/contracts/utils/contract/src/utils/index.ts deleted file mode 100644 index 14e02ef2..00000000 --- a/contracts/utils/contract/src/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { useCircuitContext as circuitContext } from './test'; diff --git a/contracts/utils/contract/src/utils/test.ts b/contracts/utils/contract/src/utils/test.ts deleted file mode 100644 index 940ed612..00000000 --- a/contracts/utils/contract/src/utils/test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - QueryContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types'; - -/** - * Constructs a `CircuitContext` from the given state and sender information. - * - * This is typically used at runtime to provide the necessary context - * for executing circuits, including contract state, private state, - * sender identity, and transaction data. - * - * @template P - The type of the contract's private state. - * @param privateState - The current private state of the contract. - * @param contractState - The full contract state, including public and private data. - * @param sender - The public key of the sender (used in the circuit). - * @param contractAddress - The address of the deployed contract. - * @returns A fully populated `CircuitContext` for circuit execution. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContext

( - privateState: P, - contractState: ContractState, - sender: CoinPublicKey, - contractAddress: ContractAddress, -): CircuitContext

{ - return { - originalState: contractState, - currentPrivateState: privateState, - transactionContext: new QueryContext(contractState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} - -/** - * Prepares a new `CircuitContext` using the given sender and contract. - * - * Useful for mocking or updating the circuit context with a custom sender. - * - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - * @template C - The specific type of the contract implementing `MockContract`. - * @param contract - The contract instance implementing `MockContract`. - * @param sender - The public key to set as the sender in the new circuit context. - * @returns A new `CircuitContext` with the sender and updated context values. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContextSender>( - contract: C, - sender: CoinPublicKey, -): CircuitContext

{ - const currentPrivateState = contract.getCurrentPrivateState(); - const originalState = contract.getCurrentContractState(); - const contractAddress = contract.contractAddress; - - return { - originalState, - currentPrivateState, - transactionContext: new QueryContext(originalState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} diff --git a/contracts/utils/contract/tsconfig.build.json b/contracts/utils/contract/tsconfig.build.json deleted file mode 100644 index f1132509..00000000 --- a/contracts/utils/contract/tsconfig.build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["src/test/**/*.ts"], - "compilerOptions": {} -} diff --git a/contracts/utils/contract/tsconfig.json b/contracts/utils/contract/tsconfig.json deleted file mode 100644 index 3e90b0a9..00000000 --- a/contracts/utils/contract/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "include": ["src/**/*.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - "declaration": true, - "lib": ["ESNext"], - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "node", - "allowJs": true, - "forceConsistentCasingInFileNames": true, - "noImplicitAny": true, - "strict": true, - "isolatedModules": true, - "sourceMap": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "skipLibCheck": true - } -} diff --git a/contracts/erc20/contract/jest.config.ts b/contracts/utils/jest.config.ts similarity index 100% rename from contracts/erc20/contract/jest.config.ts rename to contracts/utils/jest.config.ts diff --git a/contracts/erc20/contract/js-resolver.cjs b/contracts/utils/js-resolver.cjs similarity index 100% rename from contracts/erc20/contract/js-resolver.cjs rename to contracts/utils/js-resolver.cjs diff --git a/contracts/utils/contract/package.json b/contracts/utils/package.json similarity index 100% rename from contracts/utils/contract/package.json rename to contracts/utils/package.json diff --git a/contracts/utils/contract/src/MockUtils.compact b/contracts/utils/src/MockUtils.compact similarity index 81% rename from contracts/utils/contract/src/MockUtils.compact rename to contracts/utils/src/MockUtils.compact index e23c0f09..479a1fa2 100644 --- a/contracts/utils/contract/src/MockUtils.compact +++ b/contracts/utils/src/MockUtils.compact @@ -6,7 +6,7 @@ import CompactStandardLibrary; import Utils prefix Utils_; -export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; +export { ZswapCoinPublicKey, ContractAddress, Either }; export pure circuit isZero(keyOrAddress: Either): Boolean { return Utils_isZero(keyOrAddress); diff --git a/contracts/utils/contract/src/Utils.compact b/contracts/utils/src/Utils.compact similarity index 100% rename from contracts/utils/contract/src/Utils.compact rename to contracts/utils/src/Utils.compact diff --git a/contracts/utils/src/test/UtilsSimulator.ts b/contracts/utils/src/test/UtilsSimulator.ts new file mode 100644 index 00000000..98190e5c --- /dev/null +++ b/contracts/utils/src/test/UtilsSimulator.ts @@ -0,0 +1,94 @@ +import { + type CircuitContext, + type ContractState, + QueryContext, + constructorContext, +} from '@midnight-ntwrk/compact-runtime'; +import { sampleContractAddress } from '@midnight-ntwrk/zswap'; +import { + type Ledger, + Contract as MockUtils, + ledger, + Either, + ZswapCoinPublicKey, + ContractAddress, +} from '../artifacts/MockUtils/contract/index.cjs'; // Combined imports +import type { IContractSimulator } from './types'; +import { UtilsPrivateState, UtilsWitnesses } from '../witnesses'; + +/** + * @description A simulator implementation of an utils contract for testing purposes. + * @template P - The private state type, fixed to UtilsPrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class UtilsContractSimulator + implements IContractSimulator +{ + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockUtils; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor() { + this.contract = new MockUtils( + UtilsWitnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)) + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type UtilsPrivateState. + */ + public getCurrentPrivateState(): UtilsPrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + + /** + * @description Returns whether `keyOrAddress` is the zero address. + * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @returns Returns true if `keyOrAddress` is zero. + */ + public isZero(keyOrAddress: Either): boolean { + return this.contract.circuits.isZero(this.circuitContext, keyOrAddress).result; + } +} diff --git a/contracts/erc20/contract/src/test/types.ts b/contracts/utils/src/test/types/index.ts similarity index 56% rename from contracts/erc20/contract/src/test/types.ts rename to contracts/utils/src/test/types/index.ts index 4735fab2..42407d62 100644 --- a/contracts/erc20/contract/src/test/types.ts +++ b/contracts/utils/src/test/types/index.ts @@ -1,4 +1,6 @@ +export type { IContractSimulator } from './test'; + export type MaybeString = { is_some: boolean, value: string -} +} \ No newline at end of file diff --git a/contracts/erc20/contract/src/types/test.ts b/contracts/utils/src/test/types/test.ts similarity index 100% rename from contracts/erc20/contract/src/types/test.ts rename to contracts/utils/src/test/types/test.ts diff --git a/contracts/utils/contract/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts similarity index 58% rename from contracts/utils/contract/src/test/utils.test.ts rename to contracts/utils/src/test/utils.test.ts index 499ad79e..bfe6582f 100644 --- a/contracts/utils/contract/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -1,8 +1,8 @@ import { UtilsContractSimulator } from './UtilsSimulator'; -import * as utils from './utils.js'; +import * as contractUtils from './utils'; -const Z_OWNER = utils.createEitherTestUser('OWNER'); -const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); +const Z_OWNER = contractUtils.createEitherTestUser('OWNER'); +const SOME_CONTRACT = contractUtils.createEitherTestContractAddress('SOME_CONTRACT'); let contract: UtilsContractSimulator; @@ -11,8 +11,8 @@ describe('Utils', () => { describe('isZero', () => { it('should return zero for the zero address', () => { - expect(contract.isZero(utils.ZERO_KEY)).toBeTruthy; - expect(contract.isZero(utils.ZERO_ADDRESS)).toBeTruthy; + expect(contract.isZero(contractUtils.ZERO_KEY)).toBeTruthy; + expect(contract.isZero(contractUtils.ZERO_ADDRESS)).toBeTruthy; }); it('should not return zero for nonzero addresses', () => { diff --git a/contracts/erc20/contract/src/test/utils.ts b/contracts/utils/src/test/utils/address.ts similarity index 97% rename from contracts/erc20/contract/src/test/utils.ts rename to contracts/utils/src/test/utils/address.ts index d9d9778d..f6255d60 100644 --- a/contracts/erc20/contract/src/test/utils.ts +++ b/contracts/utils/src/test/utils/address.ts @@ -1,5 +1,5 @@ import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import * as Compact from '../artifacts/MockERC20/contract/index.cjs'; +import * as Compact from '../../artifacts/MockUtils/contract/index.cjs'; import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; const PREFIX_ADDRESS = "0200"; diff --git a/contracts/utils/src/test/utils/index.ts b/contracts/utils/src/test/utils/index.ts new file mode 100644 index 00000000..2668cc79 --- /dev/null +++ b/contracts/utils/src/test/utils/index.ts @@ -0,0 +1,4 @@ +export { useCircuitContext as circuitContext } from './test'; +export { + pad, encodeToPK, encodeToAddress, createEitherTestUser, createEitherTestContractAddress, ZERO_KEY, ZERO_ADDRESS +} from './address'; diff --git a/contracts/erc20/contract/src/utils/test.ts b/contracts/utils/src/test/utils/test.ts similarity index 100% rename from contracts/erc20/contract/src/utils/test.ts rename to contracts/utils/src/test/utils/test.ts diff --git a/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts b/contracts/utils/src/witnesses/UtilsWitnesses.ts similarity index 85% rename from contracts/utils/contract/src/witnesses/UtilsWitnesses.ts rename to contracts/utils/src/witnesses/UtilsWitnesses.ts index 3b7d3340..cc588fe6 100644 --- a/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts +++ b/contracts/utils/src/witnesses/UtilsWitnesses.ts @@ -1,7 +1,4 @@ // This is how we type an empty object. export type UtilsPrivateState = Record; - -export const witnesses = {}; export const UtilsWitnesses = {}; - export const createUtilsPrivateState = () => ({}); diff --git a/contracts/utils/contract/src/witnesses/index.ts b/contracts/utils/src/witnesses/index.ts similarity index 100% rename from contracts/utils/contract/src/witnesses/index.ts rename to contracts/utils/src/witnesses/index.ts diff --git a/contracts/erc20/contract/tsconfig.build.json b/contracts/utils/tsconfig.build.json similarity index 100% rename from contracts/erc20/contract/tsconfig.build.json rename to contracts/utils/tsconfig.build.json diff --git a/contracts/erc20/contract/tsconfig.json b/contracts/utils/tsconfig.json similarity index 100% rename from contracts/erc20/contract/tsconfig.json rename to contracts/utils/tsconfig.json diff --git a/yarn.lock b/yarn.lock index cee6bf04..b34a47b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1119,17 +1119,6 @@ __metadata: languageName: unknown linkType: soft -"@openzeppelin-midnight-contracts/utils-contract@workspace:^, @openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils/contract": - version: 0.0.0-use.local - resolution: "@openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils/contract" - dependencies: - "@midnight-ntwrk/compact": "workspace:*" - eslint: "npm:^8.52.0" - jest: "npm:^29.7.0" - typescript: "npm:^5.2.2" - languageName: unknown - linkType: soft - "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" From 1eb43389b25130b95433595c2441ba53c2188e8e Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 00:14:24 -0500 Subject: [PATCH 009/282] remove unused var --- contracts/utils/src/witnesses/UtilsWitnesses.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/utils/src/witnesses/UtilsWitnesses.ts b/contracts/utils/src/witnesses/UtilsWitnesses.ts index cc588fe6..b33baa56 100644 --- a/contracts/utils/src/witnesses/UtilsWitnesses.ts +++ b/contracts/utils/src/witnesses/UtilsWitnesses.ts @@ -1,4 +1,3 @@ // This is how we type an empty object. export type UtilsPrivateState = Record; export const UtilsWitnesses = {}; -export const createUtilsPrivateState = () => ({}); From b77ab082ac27f280f65599722f6587d82eeefe1d Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 02:07:16 -0500 Subject: [PATCH 010/282] fix structure --- contracts/utils/{ => contract}/.eslintignore | 0 contracts/utils/{ => contract}/.eslintrc.cjs | 0 contracts/utils/{ => contract}/jest.config.ts | 0 contracts/utils/{ => contract}/js-resolver.cjs | 0 contracts/utils/{ => contract}/package.json | 0 contracts/utils/{ => contract}/src/MockUtils.compact | 0 contracts/utils/{ => contract}/src/Utils.compact | 0 .../utils/{ => contract}/src/test/UtilsSimulator.ts | 0 .../utils/{ => contract}/src/test/types/index.ts | 0 contracts/utils/{ => contract}/src/test/types/test.ts | 0 contracts/utils/{ => contract}/src/test/utils.test.ts | 4 ++-- .../utils/{ => contract}/src/test/utils/address.ts | 0 .../utils/{ => contract}/src/test/utils/index.ts | 0 contracts/utils/{ => contract}/src/test/utils/test.ts | 0 .../{ => contract}/src/witnesses/UtilsWitnesses.ts | 0 contracts/utils/{ => contract}/src/witnesses/index.ts | 0 contracts/utils/{ => contract}/tsconfig.build.json | 0 contracts/utils/{ => contract}/tsconfig.json | 0 yarn.lock | 11 +++++++++++ 19 files changed, 13 insertions(+), 2 deletions(-) rename contracts/utils/{ => contract}/.eslintignore (100%) rename contracts/utils/{ => contract}/.eslintrc.cjs (100%) rename contracts/utils/{ => contract}/jest.config.ts (100%) rename contracts/utils/{ => contract}/js-resolver.cjs (100%) rename contracts/utils/{ => contract}/package.json (100%) rename contracts/utils/{ => contract}/src/MockUtils.compact (100%) rename contracts/utils/{ => contract}/src/Utils.compact (100%) rename contracts/utils/{ => contract}/src/test/UtilsSimulator.ts (100%) rename contracts/utils/{ => contract}/src/test/types/index.ts (100%) rename contracts/utils/{ => contract}/src/test/types/test.ts (100%) rename contracts/utils/{ => contract}/src/test/utils.test.ts (84%) rename contracts/utils/{ => contract}/src/test/utils/address.ts (100%) rename contracts/utils/{ => contract}/src/test/utils/index.ts (100%) rename contracts/utils/{ => contract}/src/test/utils/test.ts (100%) rename contracts/utils/{ => contract}/src/witnesses/UtilsWitnesses.ts (100%) rename contracts/utils/{ => contract}/src/witnesses/index.ts (100%) rename contracts/utils/{ => contract}/tsconfig.build.json (100%) rename contracts/utils/{ => contract}/tsconfig.json (100%) diff --git a/contracts/utils/.eslintignore b/contracts/utils/contract/.eslintignore similarity index 100% rename from contracts/utils/.eslintignore rename to contracts/utils/contract/.eslintignore diff --git a/contracts/utils/.eslintrc.cjs b/contracts/utils/contract/.eslintrc.cjs similarity index 100% rename from contracts/utils/.eslintrc.cjs rename to contracts/utils/contract/.eslintrc.cjs diff --git a/contracts/utils/jest.config.ts b/contracts/utils/contract/jest.config.ts similarity index 100% rename from contracts/utils/jest.config.ts rename to contracts/utils/contract/jest.config.ts diff --git a/contracts/utils/js-resolver.cjs b/contracts/utils/contract/js-resolver.cjs similarity index 100% rename from contracts/utils/js-resolver.cjs rename to contracts/utils/contract/js-resolver.cjs diff --git a/contracts/utils/package.json b/contracts/utils/contract/package.json similarity index 100% rename from contracts/utils/package.json rename to contracts/utils/contract/package.json diff --git a/contracts/utils/src/MockUtils.compact b/contracts/utils/contract/src/MockUtils.compact similarity index 100% rename from contracts/utils/src/MockUtils.compact rename to contracts/utils/contract/src/MockUtils.compact diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/contract/src/Utils.compact similarity index 100% rename from contracts/utils/src/Utils.compact rename to contracts/utils/contract/src/Utils.compact diff --git a/contracts/utils/src/test/UtilsSimulator.ts b/contracts/utils/contract/src/test/UtilsSimulator.ts similarity index 100% rename from contracts/utils/src/test/UtilsSimulator.ts rename to contracts/utils/contract/src/test/UtilsSimulator.ts diff --git a/contracts/utils/src/test/types/index.ts b/contracts/utils/contract/src/test/types/index.ts similarity index 100% rename from contracts/utils/src/test/types/index.ts rename to contracts/utils/contract/src/test/types/index.ts diff --git a/contracts/utils/src/test/types/test.ts b/contracts/utils/contract/src/test/types/test.ts similarity index 100% rename from contracts/utils/src/test/types/test.ts rename to contracts/utils/contract/src/test/types/test.ts diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/contract/src/test/utils.test.ts similarity index 84% rename from contracts/utils/src/test/utils.test.ts rename to contracts/utils/contract/src/test/utils.test.ts index bfe6582f..87456c88 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/contract/src/test/utils.test.ts @@ -1,7 +1,7 @@ import { UtilsContractSimulator } from './UtilsSimulator'; import * as contractUtils from './utils'; -const Z_OWNER = contractUtils.createEitherTestUser('OWNER'); +const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); const SOME_CONTRACT = contractUtils.createEitherTestContractAddress('SOME_CONTRACT'); let contract: UtilsContractSimulator; @@ -16,7 +16,7 @@ describe('Utils', () => { }); it('should not return zero for nonzero addresses', () => { - expect(contract.isZero(Z_OWNER)).toBeFalsy; + expect(contract.isZero(Z_SOME_KEY)).toBeFalsy; expect(contract.isZero(SOME_CONTRACT)).toBeFalsy; }); }); diff --git a/contracts/utils/src/test/utils/address.ts b/contracts/utils/contract/src/test/utils/address.ts similarity index 100% rename from contracts/utils/src/test/utils/address.ts rename to contracts/utils/contract/src/test/utils/address.ts diff --git a/contracts/utils/src/test/utils/index.ts b/contracts/utils/contract/src/test/utils/index.ts similarity index 100% rename from contracts/utils/src/test/utils/index.ts rename to contracts/utils/contract/src/test/utils/index.ts diff --git a/contracts/utils/src/test/utils/test.ts b/contracts/utils/contract/src/test/utils/test.ts similarity index 100% rename from contracts/utils/src/test/utils/test.ts rename to contracts/utils/contract/src/test/utils/test.ts diff --git a/contracts/utils/src/witnesses/UtilsWitnesses.ts b/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts similarity index 100% rename from contracts/utils/src/witnesses/UtilsWitnesses.ts rename to contracts/utils/contract/src/witnesses/UtilsWitnesses.ts diff --git a/contracts/utils/src/witnesses/index.ts b/contracts/utils/contract/src/witnesses/index.ts similarity index 100% rename from contracts/utils/src/witnesses/index.ts rename to contracts/utils/contract/src/witnesses/index.ts diff --git a/contracts/utils/tsconfig.build.json b/contracts/utils/contract/tsconfig.build.json similarity index 100% rename from contracts/utils/tsconfig.build.json rename to contracts/utils/contract/tsconfig.build.json diff --git a/contracts/utils/tsconfig.json b/contracts/utils/contract/tsconfig.json similarity index 100% rename from contracts/utils/tsconfig.json rename to contracts/utils/contract/tsconfig.json diff --git a/yarn.lock b/yarn.lock index b34a47b0..378e2992 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1119,6 +1119,17 @@ __metadata: languageName: unknown linkType: soft +"@openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils/contract": + version: 0.0.0-use.local + resolution: "@openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils/contract" + dependencies: + "@midnight-ntwrk/compact": "workspace:*" + eslint: "npm:^8.52.0" + jest: "npm:^29.7.0" + typescript: "npm:^5.2.2" + languageName: unknown + linkType: soft + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" From a97e80e2aa85e0763c95853286906ea2aa3a68f0 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 02:08:50 -0500 Subject: [PATCH 011/282] remove comment --- contracts/utils/contract/src/Utils.compact | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/utils/contract/src/Utils.compact b/contracts/utils/contract/src/Utils.compact index b0dbf3f5..80f59f78 100644 --- a/contracts/utils/contract/src/Utils.compact +++ b/contracts/utils/contract/src/Utils.compact @@ -7,7 +7,6 @@ module Utils { /** * @description Returns whether `keyOrAddress` is the zero address. - * @todo Move to a utils contract since this will likely be reused. * * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @return {Boolean} - Returns true if `keyOrAddress` is zero. From e766600b6fad31682056a1341c9d9b614695ac11 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 02:24:56 -0500 Subject: [PATCH 012/282] improve circuit name --- contracts/utils/contract/src/MockUtils.compact | 4 ++-- contracts/utils/contract/src/Utils.compact | 2 +- contracts/utils/contract/src/test/UtilsSimulator.ts | 4 ++-- contracts/utils/contract/src/test/utils.test.ts | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/contracts/utils/contract/src/MockUtils.compact b/contracts/utils/contract/src/MockUtils.compact index 479a1fa2..f2263768 100644 --- a/contracts/utils/contract/src/MockUtils.compact +++ b/contracts/utils/contract/src/MockUtils.compact @@ -8,6 +8,6 @@ import Utils prefix Utils_; export { ZswapCoinPublicKey, ContractAddress, Either }; -export pure circuit isZero(keyOrAddress: Either): Boolean { - return Utils_isZero(keyOrAddress); +export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { + return Utils_isKeyOrAddressZero(keyOrAddress); } diff --git a/contracts/utils/contract/src/Utils.compact b/contracts/utils/contract/src/Utils.compact index 80f59f78..26a9bc84 100644 --- a/contracts/utils/contract/src/Utils.compact +++ b/contracts/utils/contract/src/Utils.compact @@ -11,7 +11,7 @@ module Utils { * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @return {Boolean} - Returns true if `keyOrAddress` is zero. */ - export pure circuit isZero(keyOrAddress: Either): Boolean { + export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { const zero = pad(32, ""); if (keyOrAddress.is_left) { diff --git a/contracts/utils/contract/src/test/UtilsSimulator.ts b/contracts/utils/contract/src/test/UtilsSimulator.ts index 98190e5c..c55c802f 100644 --- a/contracts/utils/contract/src/test/UtilsSimulator.ts +++ b/contracts/utils/contract/src/test/UtilsSimulator.ts @@ -88,7 +88,7 @@ export class UtilsContractSimulator * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @returns Returns true if `keyOrAddress` is zero. */ - public isZero(keyOrAddress: Either): boolean { - return this.contract.circuits.isZero(this.circuitContext, keyOrAddress).result; + public isKeyOrAddressZero(keyOrAddress: Either): boolean { + return this.contract.circuits.isKeyOrAddressZero(this.circuitContext, keyOrAddress).result; } } diff --git a/contracts/utils/contract/src/test/utils.test.ts b/contracts/utils/contract/src/test/utils.test.ts index 87456c88..22aa0698 100644 --- a/contracts/utils/contract/src/test/utils.test.ts +++ b/contracts/utils/contract/src/test/utils.test.ts @@ -11,13 +11,13 @@ describe('Utils', () => { describe('isZero', () => { it('should return zero for the zero address', () => { - expect(contract.isZero(contractUtils.ZERO_KEY)).toBeTruthy; - expect(contract.isZero(contractUtils.ZERO_ADDRESS)).toBeTruthy; + expect(contract.isKeyOrAddressZero(contractUtils.ZERO_KEY)).toBeTruthy; + expect(contract.isKeyOrAddressZero(contractUtils.ZERO_ADDRESS)).toBeTruthy; }); it('should not return zero for nonzero addresses', () => { - expect(contract.isZero(Z_SOME_KEY)).toBeFalsy; - expect(contract.isZero(SOME_CONTRACT)).toBeFalsy; + expect(contract.isKeyOrAddressZero(Z_SOME_KEY)).toBeFalsy; + expect(contract.isKeyOrAddressZero(SOME_CONTRACT)).toBeFalsy; }); }); }); From 07e15da0e8fb6dbf1c10e4882b1d9d2beab06bbc Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 02:48:29 -0500 Subject: [PATCH 013/282] add line --- contracts/utils/contract/src/test/types/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/contract/src/test/types/index.ts b/contracts/utils/contract/src/test/types/index.ts index 42407d62..dac4e694 100644 --- a/contracts/utils/contract/src/test/types/index.ts +++ b/contracts/utils/contract/src/test/types/index.ts @@ -3,4 +3,4 @@ export type { IContractSimulator } from './test'; export type MaybeString = { is_some: boolean, value: string -} \ No newline at end of file +} From 199689840bb9c2edf83b09834ca19681b691d2b1 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 02:49:20 -0500 Subject: [PATCH 014/282] fix test describe --- contracts/utils/contract/src/test/utils.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/contract/src/test/utils.test.ts b/contracts/utils/contract/src/test/utils.test.ts index 22aa0698..a24fc902 100644 --- a/contracts/utils/contract/src/test/utils.test.ts +++ b/contracts/utils/contract/src/test/utils.test.ts @@ -9,7 +9,7 @@ let contract: UtilsContractSimulator; describe('Utils', () => { contract = new UtilsContractSimulator(); - describe('isZero', () => { + describe('isKeyOrAddressZero', () => { it('should return zero for the zero address', () => { expect(contract.isKeyOrAddressZero(contractUtils.ZERO_KEY)).toBeTruthy; expect(contract.isKeyOrAddressZero(contractUtils.ZERO_ADDRESS)).toBeTruthy; From af7d5d84fa1c48876c9e9846424e7c3193c5a469 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 02:50:57 -0500 Subject: [PATCH 015/282] add line --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 61a5f3e1..0365a1c8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,4 +14,4 @@ trim_trailing_whitespace = false max_line_length = 80 [*.ts] -max_line_length = 100 \ No newline at end of file +max_line_length = 100 From 72f6b0db7bdbe9340cc7c6aa6eb66cb21c7568f0 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 31 Mar 2025 16:51:00 -0500 Subject: [PATCH 016/282] remove token dir --- .../erc721/contract/src/test/erc721-setup.ts | 108 ------- .../erc721/contract/src/test/erc721.test.ts | 279 ------------------ contracts/erc721/contract/src/test/types.ts | 4 - contracts/erc721/contract/src/test/utils.ts | 78 ----- contracts/utils/contract/.eslintignore | 1 - contracts/utils/contract/.eslintrc.cjs | 30 -- contracts/utils/contract/jest.config.ts | 28 -- contracts/utils/contract/js-resolver.cjs | 16 - contracts/utils/contract/package.json | 29 -- contracts/utils/contract/tsconfig.build.json | 5 - contracts/utils/contract/tsconfig.json | 21 -- 11 files changed, 599 deletions(-) delete mode 100644 contracts/erc721/contract/src/test/erc721-setup.ts delete mode 100644 contracts/erc721/contract/src/test/erc721.test.ts delete mode 100644 contracts/erc721/contract/src/test/types.ts delete mode 100644 contracts/erc721/contract/src/test/utils.ts delete mode 100644 contracts/utils/contract/.eslintignore delete mode 100644 contracts/utils/contract/.eslintrc.cjs delete mode 100644 contracts/utils/contract/jest.config.ts delete mode 100644 contracts/utils/contract/js-resolver.cjs delete mode 100644 contracts/utils/contract/package.json delete mode 100644 contracts/utils/contract/tsconfig.build.json delete mode 100644 contracts/utils/contract/tsconfig.json diff --git a/contracts/erc721/contract/src/test/erc721-setup.ts b/contracts/erc721/contract/src/test/erc721-setup.ts deleted file mode 100644 index 6b1be532..00000000 --- a/contracts/erc721/contract/src/test/erc721-setup.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { type CircuitContext, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; -import { Contract, type Ledger, ledger, ZswapCoinPublicKey, ContractAddress, Either } from '../artifacts/erc20/contract/index.cjs'; -import { type ERC20PrivateState, witnesses } from '../witnesses.js'; -import { MaybeString } from './types.js'; - -export class ERC20Mock { - readonly contract: Contract; - readonly contractAddress: string; - circuitContext: CircuitContext; - - constructor(name: MaybeString, symbol: MaybeString, decimals: bigint) { - this.contract = new Contract(witnesses); - const { currentPrivateState, currentContractState, currentZswapLocalState } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)), name, symbol, decimals - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext(currentContractState.data, sampleContractAddress()), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - public getLedger(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - public getPrivateState(): ERC20PrivateState { - return this.circuitContext.currentPrivateState; - } - - public balanceOf(account: Either): bigint { - return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; - } - - public allowance( - owner: Either, - spender: Either - ): bigint { - return this.contract.impureCircuits.allowance(this.circuitContext, owner, spender).result; - } - - public transfer(to: Either, value: bigint): boolean { - return this.contract.impureCircuits.transfer(this.circuitContext, to, value).result; - } - - public transferFrom( - from: Either, - to: Either, - value: bigint - ): boolean { - return this.contract.impureCircuits.transferFrom(this.circuitContext, from, to, value).result; - } - - public approve(spender: Either, value: bigint): boolean { - return this.contract.impureCircuits.approve(this.circuitContext, spender, value).result; - } - - public _approve( - owner: Either, - spender: Either, - value: bigint - ) { - this.circuitContext = this.contract.impureCircuits._approve(this.circuitContext, owner, spender, value).context; - return ledger(this.circuitContext.transactionContext.state); - } - - public _transfer( - from: Either, - to: Either, - value: bigint - ) { - this.circuitContext = this.contract.impureCircuits._transfer(this.circuitContext, from, to, value).context; - return ledger(this.circuitContext.transactionContext.state); - } - - public _mint(account: Either, value: bigint) { - this.circuitContext = this.contract.impureCircuits._mint(this.circuitContext, account, value).context; - return ledger(this.circuitContext.transactionContext.state); - } - - public _burn(account: Either, value: bigint) { - this.circuitContext = this.contract.impureCircuits._burn(this.circuitContext, account, value).context; - return ledger(this.circuitContext.transactionContext.state); - } - public _update( - from: Either, - to: Either, - value: bigint - ) { - this.circuitContext = this.contract.impureCircuits._update(this.circuitContext, from, to, value).context; - return ledger(this.circuitContext.transactionContext.state); - } - - public _spendAllowance( - owner: Either, - spender: Either, - value: bigint - ) { - this.circuitContext = this.contract.impureCircuits._spendAllowance(this.circuitContext, owner, spender, value).context; - return ledger(this.circuitContext.transactionContext.state); - } - - public _isZero(address: Either): boolean { - return this.contract.circuits._isZero(this.circuitContext, address).result; - } -} diff --git a/contracts/erc721/contract/src/test/erc721.test.ts b/contracts/erc721/contract/src/test/erc721.test.ts deleted file mode 100644 index e1274631..00000000 --- a/contracts/erc721/contract/src/test/erc721.test.ts +++ /dev/null @@ -1,279 +0,0 @@ -import { it, describe, expect } from '@jest/globals'; -import { ERC20Mock } from './erc721-setup.js'; -import { NetworkId, setNetworkId } from '@midnight-ntwrk/midnight-js-network-id'; -import { MaybeString } from './types.js'; -import * as utils from './utils.js'; - -// -// Test vals -// - -const NO_STRING: MaybeString = { - is_some: false, - value: '' -}; -const NAME: MaybeString = { - is_some: true, - value: "NAME" -}; -const SYMBOL: MaybeString = { - is_some: true, - value: "SYMBOL" -}; -const DECIMALS: bigint = 18n; - -const AMOUNT: bigint = BigInt(250); -const MAX_UINT64 = BigInt(2 ** 64) - BigInt(1); -const MAX_UINT256 = BigInt(2 ** 256) - BigInt(1); - -const OWNER = utils.createEitherTestUser('OWNER'); -const RECIPIENT = utils.createEitherTestUser('RECIPIENT'); -const SPENDER = utils.createEitherTestUser('SPENDER'); -const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); - -// -// Test -// - -setNetworkId(NetworkId.Undeployed); -let token: any; - -describe('ERC20', () => { - beforeEach(() => { - token = new ERC20Mock(NAME, SYMBOL, DECIMALS); - }); - - describe('initialize', () => { - it('initializes the correct state', () => { - const state = token.getLedger(); - - expect(state.totalSupply).toEqual(0n); - expect(state.name).toEqual(NAME); - expect(state.symbol).toEqual(SYMBOL); - expect(state.decimals).toEqual(DECIMALS); - }); - - it('initializes no metadata state', () => { - const noDecimals: bigint = 0n; - - const token = new ERC20Mock(NO_STRING, NO_STRING, noDecimals); - const state = token.getLedger(); - - expect(state.totalSupply).toEqual(0n); - expect(state.name).toEqual(NO_STRING); - expect(state.symbol).toEqual(NO_STRING); - expect(state.decimals).toEqual(0n); - }); - }); - - describe('approve', () => { - // TODO: change caller context to test IERC20 interface - it.skip('should approve', () => { - const initAllowance = token.allowance(OWNER, SPENDER); - expect(initAllowance).toEqual(0n); - - token._mint(OWNER, AMOUNT); - token.approve(SPENDER, AMOUNT); - }); - }) - - describe('_approve', () => { - it('should _approve', () => { - const initAllowance = token.allowance(OWNER, SPENDER); - expect(initAllowance).toEqual(0n); - - token._approve(OWNER, SPENDER, AMOUNT); - - expect(token.allowance(OWNER, SPENDER)).toEqual(initAllowance + AMOUNT); - }); - - it('should approve to a new spender address', () => { - token._approve(OWNER, SPENDER, AMOUNT); - expect(token.allowance(OWNER, SPENDER)).toEqual(AMOUNT); - - const NEW_SPENDER = utils.createEitherTestUser('NEW_SPENDER'); - const newAmount = AMOUNT + 200n; - expect(token.allowance(OWNER, NEW_SPENDER)).toEqual(0n); - token._approve(OWNER, NEW_SPENDER, newAmount); - - expect(token.allowance(OWNER, NEW_SPENDER)).toEqual(newAmount); - expect(token.allowance(OWNER, SPENDER)).toEqual(AMOUNT); - }); - - it('should throw when owner is zero', () => { - expect(() => { - token._approve(utils.ZERO_KEY, SPENDER, AMOUNT); - }).toThrow('ERC20: invalid owner'); - }); - - it('should throw when spender is zero', () => { - expect(() => { - token._approve(OWNER, utils.ZERO_KEY, AMOUNT); - }).toThrow('ERC20: invalid spender'); - }); - }); - - describe('_spendAllowance', () => { - describe('spend allowance when not infinite', () => { - beforeEach(() => { - token._approve(OWNER, SPENDER, AMOUNT); - expect(token.allowance(OWNER, SPENDER)).toEqual(AMOUNT); - }) - - it('spends allowance', () => { - token._spendAllowance(OWNER, SPENDER, AMOUNT); - expect(token.allowance(OWNER, SPENDER)).toEqual(0n); - }); - - it('spends partial allowance', () => { - const partialAllowance = AMOUNT - 1n; - token._spendAllowance(OWNER, SPENDER, partialAllowance); - expect(token.allowance(OWNER, SPENDER)).toEqual(1n); - }); - - it('throws when not enough allowance', () => { - expect(() => { - token._spendAllowance(OWNER, SPENDER, AMOUNT + 1n); - }).toThrow('ERC20: insufficient allowance'); - }); - }); - - describe('infinite allowance', () => { - beforeEach(() => { - token._approve(OWNER, SPENDER, MAX_UINT256); - expect(token.allowance(OWNER, SPENDER)).toEqual(MAX_UINT256); - }); - - it('should not subtract from infinite allowance', () => { - token._spendAllowance(OWNER, SPENDER, MAX_UINT256 - 1n); - - expect(token.allowance(OWNER, SPENDER)).toEqual(MAX_UINT256); - }); - }); - }); - - describe('transferFrom', () => { - beforeEach(() => { - token._mint(OWNER, AMOUNT); - }); - - it.skip('should transfer from owner to recipient', () => { - const ownerBal = token.balanceOf(OWNER); - const recipientBal = token.balanceOf(RECIPIENT); - - token.transferFrom(OWNER, RECIPIENT, AMOUNT); - }) - }) - - describe('transfer', () => { - beforeEach(() => { - token._mint(OWNER, AMOUNT); - }); - - describe('internal _transfer', () => { - it('should _transfer', () => { - const ownerBal = token.balanceOf(OWNER); - const recipientBal = token.balanceOf(RECIPIENT); - - token._transfer(OWNER, RECIPIENT, AMOUNT); - - expect(token.balanceOf(OWNER)).toEqual(ownerBal - AMOUNT); - expect(token.balanceOf(RECIPIENT)).toEqual(recipientBal + AMOUNT); - - // Confirm totalSupply doesn't change - expect(token.getLedger().totalSupply).toEqual(AMOUNT); - }); - - it('throws when _transfer with not enough balance', () => { - expect(() => { - token._transfer(OWNER, RECIPIENT, AMOUNT + 1n); - }).toThrow('ERC20: insufficient balance'); - }); - }); - }); - - describe('mint', () => { - it('should mint and update supply', () => { - const initSupply = token.getLedger().totalSupply; - expect(initSupply).toEqual(0n); - - token._mint(RECIPIENT, AMOUNT); - expect(token.getLedger().totalSupply).toEqual(AMOUNT); - expect(token.balanceOf(RECIPIENT)).toEqual(AMOUNT); - }); - - it('should not mint to zero pubkey', () => { - expect(() => { - token._mint(utils.ZERO_KEY, AMOUNT); - }).toThrow('ERC20: invalid receiver'); - }); - - it('should not mint to zero contract address', () => { - expect(() => { - token._mint(utils.ZERO_ADDRESS, AMOUNT); - }).toThrow('ERC20: invalid receiver'); - }); - }); - - describe('burn', () => { - beforeEach(() => { - token._mint(OWNER, AMOUNT); - }); - - it('should burn tokens', () => { - token._burn(OWNER, 1n); - - const afterBurn = AMOUNT - 1n; - expect(token.balanceOf(OWNER)).toEqual(afterBurn); - expect(token.getLedger().totalSupply).toEqual(afterBurn) - }); - - it('should throw when burning from zero', () => { - expect(() => { - token._burn(utils.ZERO_KEY, AMOUNT); - }).toThrow('ERC20: invalid sender'); - }); - - it('should throw when burn amount is greater than balance', () => { - expect(() => { - token._burn(OWNER, AMOUNT + 1n); - }).toThrow('ERC20: insufficient balance'); - }); - }); - - describe('_update', () => { - it('should update from zero to non-zero (mint)', () => { - expect(token.getLedger().totalSupply).toEqual(0n); - expect(token.balanceOf(OWNER)).toEqual(0n); - - token._update(utils.ZERO_KEY, OWNER, AMOUNT); - - expect(token.getLedger().totalSupply).toEqual(AMOUNT); - expect(token.balanceOf(OWNER)).toEqual(AMOUNT); - }); - - describe('with minted tokens', () => { - beforeEach(() => { - token._update(utils.ZERO_ADDRESS, OWNER, AMOUNT); - - expect(token.getLedger().totalSupply).toEqual(AMOUNT); - expect(token.balanceOf(OWNER)).toEqual(AMOUNT); - }); - - it('should update from non-zero to zero (burn)', () => { - token._update(OWNER, utils.ZERO_ADDRESS, AMOUNT); - - expect(token.getLedger().totalSupply).toEqual(0n); - expect(token.balanceOf(OWNER)).toEqual(0n); - }); - - it('should update from non-zero to non-zero (transfer)', () => { - token._update(OWNER, RECIPIENT, AMOUNT - 1n); - - expect(token.getLedger().totalSupply).toEqual(AMOUNT); - expect(token.balanceOf(OWNER)).toEqual(1n); - expect(token.balanceOf(RECIPIENT)).toEqual(AMOUNT - 1n); - }); - }); - }); -}); diff --git a/contracts/erc721/contract/src/test/types.ts b/contracts/erc721/contract/src/test/types.ts deleted file mode 100644 index 4735fab2..00000000 --- a/contracts/erc721/contract/src/test/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type MaybeString = { - is_some: boolean, - value: string -} diff --git a/contracts/erc721/contract/src/test/utils.ts b/contracts/erc721/contract/src/test/utils.ts deleted file mode 100644 index 1e060552..00000000 --- a/contracts/erc721/contract/src/test/utils.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import * as Compact from '../artifacts/erc721/contract/index.cjs'; -import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; - -const PREFIX_ADDRESS = "0200"; - -export const pad = (s: string, n: number): Uint8Array => { - const encoder = new TextEncoder(); - const utf8Bytes = encoder.encode(s); - if (n < utf8Bytes.length) { - throw new Error(`The padded length n must be at least ${utf8Bytes.length}`); - } - const paddedArray = new Uint8Array(n); - paddedArray.set(utf8Bytes); - return paddedArray; -} - -/** - * @description Generates ZswapCoinPublicKey from `str` for testing purposes. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; -} - -/** - * @description Generates ContractAddress from `str` for testing purposes. - * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToAddress = (str: string): Compact.ContractAddress => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); - return { bytes: encodeContractAddress(fullAddress) }; -} - -/** - * @description Generates an Either object for ZswapCoinPublicKey for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ZswapCoinPublicKey. - */ -export const createEitherTestUser = (str: string) => { - return { - is_left: true, - left: encodeToPK(str), - right: encodeToAddress('') - } -} - -/** - * @description Generates an Either object for ContractAddress for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ContractAddress. - */ -export const createEitherTestContractAddress = (str: string) => { - return { - is_left: false, - left: encodeToPK(''), - right: encodeToAddress(str) - } -} - -export const ZERO_KEY = { - is_left: true, - left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, - right: encodeToAddress('') -} - -export const ZERO_ADDRESS = { - is_left: false, - left: encodeToPK(''), - right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) } -} diff --git a/contracts/utils/contract/.eslintignore b/contracts/utils/contract/.eslintignore deleted file mode 100644 index 652df825..00000000 --- a/contracts/utils/contract/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -src/managed diff --git a/contracts/utils/contract/.eslintrc.cjs b/contracts/utils/contract/.eslintrc.cjs deleted file mode 100644 index 581f1d49..00000000 --- a/contracts/utils/contract/.eslintrc.cjs +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - node: true, - jest: true, - }, - extends: [ - 'standard-with-typescript', - 'plugin:prettier/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - overrides: [], - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['tsconfig.json'], - }, - rules: { - '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 - '@typescript-eslint/no-floating-promises': 'warn', - '@typescript-eslint/promise-function-async': 'off', - '@typescript-eslint/no-redeclare': 'off', - '@typescript-eslint/no-invalid-void-type': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/consistent-type-definitions': 'off' - }, -}; diff --git a/contracts/utils/contract/jest.config.ts b/contracts/utils/contract/jest.config.ts deleted file mode 100644 index edbdaeba..00000000 --- a/contracts/utils/contract/jest.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Config } from "@jest/types"; - -const config: Config.InitialOptions = { - preset: "ts-jest/presets/default-esm", - testEnvironment: "node", - verbose: true, - roots: [""], - modulePaths: [""], - passWithNoTests: false, - testMatch: ["**/*.test.ts"], - extensionsToTreatAsEsm: [".ts"], - collectCoverage: true, - resolver: '/js-resolver.cjs', - coverageThreshold: { - global: { - //branches: 60, - //functions: 75, - //lines: 70, - }, - }, - reporters: [ - "default", - ["jest-junit", { outputDirectory: "reports", outputName: "report.xml" }], - ["jest-html-reporters", { publicPath: "reports", filename: "report.html" }], - ], -}; - -export default config; diff --git a/contracts/utils/contract/js-resolver.cjs b/contracts/utils/contract/js-resolver.cjs deleted file mode 100644 index cc9ed285..00000000 --- a/contracts/utils/contract/js-resolver.cjs +++ /dev/null @@ -1,16 +0,0 @@ -const jsResolver = (path, options) => { - const jsExtRegex = /\.js$/i - const resolver = options.defaultResolver - if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { - const newPath = path.replace(jsExtRegex, '.ts'); - try { - return resolver(newPath, options) - } catch { - // use default resolver - } - } - - return resolver(path, options) -} - -module.exports = jsResolver diff --git a/contracts/utils/contract/package.json b/contracts/utils/contract/package.json deleted file mode 100644 index 40c57157..00000000 --- a/contracts/utils/contract/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "@openzeppelin-midnight-contracts/utils-contract", - "type": "module", - "main": "dist/index.js", - "module": "dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "require": "./dist/index.js", - "import": "./dist/index.js", - "default": "./dist/index.js" - } - }, - "scripts": { - "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", - "test": "NODE_OPTIONS=--experimental-vm-modules jest", - "prepack": "yarn build", - "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/Utils.compact ./dist", - "lint": "eslint src", - "typecheck": "tsc -p tsconfig.json --noEmit" - }, - "devDependencies": { - "@midnight-ntwrk/compact": "workspace:*", - "eslint": "^8.52.0", - "jest": "^29.7.0", - "typescript": "^5.2.2" - } -} diff --git a/contracts/utils/contract/tsconfig.build.json b/contracts/utils/contract/tsconfig.build.json deleted file mode 100644 index f1132509..00000000 --- a/contracts/utils/contract/tsconfig.build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["src/test/**/*.ts"], - "compilerOptions": {} -} diff --git a/contracts/utils/contract/tsconfig.json b/contracts/utils/contract/tsconfig.json deleted file mode 100644 index 3e90b0a9..00000000 --- a/contracts/utils/contract/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "include": ["src/**/*.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - "declaration": true, - "lib": ["ESNext"], - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "node", - "allowJs": true, - "forceConsistentCasingInFileNames": true, - "noImplicitAny": true, - "strict": true, - "isolatedModules": true, - "sourceMap": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "skipLibCheck": true - } -} From ac1f839658b4804b42f60f230104c61afe375028 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 31 Mar 2025 17:44:00 -0500 Subject: [PATCH 017/282] change managed to artifacts --- contracts/initializable/contract/.eslintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/initializable/contract/.eslintignore b/contracts/initializable/contract/.eslintignore index 652df825..327555cd 100644 --- a/contracts/initializable/contract/.eslintignore +++ b/contracts/initializable/contract/.eslintignore @@ -1 +1 @@ -src/managed +src/artifacts From 06cbd5965c1f2faaaf6b021416dbe46e135cff0c Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 31 Mar 2025 17:44:30 -0500 Subject: [PATCH 018/282] remove .vscode dir --- .../contract/.vscode/launch.json | 19 -------------- .../initializable/contract/.vscode/tasks.json | 25 ------------------- 2 files changed, 44 deletions(-) delete mode 100644 contracts/initializable/contract/.vscode/launch.json delete mode 100644 contracts/initializable/contract/.vscode/tasks.json diff --git a/contracts/initializable/contract/.vscode/launch.json b/contracts/initializable/contract/.vscode/launch.json deleted file mode 100644 index 15021ab9..00000000 --- a/contracts/initializable/contract/.vscode/launch.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "Launch Compact debug", - "program": "${file}", - "skipFiles": [ - "/**" - ], - "outFiles": [ - "${workspaceFolder}/**/*.js", - "${workspaceFolder}/**/*.cjs" - ] - } - ] - } - diff --git a/contracts/initializable/contract/.vscode/tasks.json b/contracts/initializable/contract/.vscode/tasks.json deleted file mode 100644 index bffefefe..00000000 --- a/contracts/initializable/contract/.vscode/tasks.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "Compile compact file to JS", - "type": "shell", - "command": "npx run-compactc --skip-zk ${file} ${workspaceFolder}/src/managed", - "group": "build", - "presentation": { - "echo": true, - "reveal": "never", - "focus": false, - "panel": "shared", - "showReuseMessage": false, - "clear": true, - "revealProblems": "onProblem" - }, - "problemMatcher": [ - "$compactException", - "$compactInternal", - "$compactCommandNotFound" - ] - } - ] -} From 110db8cd22f8ca5e98e9e4e3d11ad5535dc554da Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:43:13 -0500 Subject: [PATCH 019/282] change coverage --- contracts/initializable/contract/jest.config.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/initializable/contract/jest.config.ts b/contracts/initializable/contract/jest.config.ts index b57dc4ed..3cbccc1b 100644 --- a/contracts/initializable/contract/jest.config.ts +++ b/contracts/initializable/contract/jest.config.ts @@ -13,9 +13,9 @@ const config: Config.InitialOptions = { resolver: '/js-resolver.cjs', coverageThreshold: { global: { - branches: 60, - functions: 75, - lines: 70, + branches: 50, + functions: 50, + lines: 50, }, }, reporters: [ From 298006136b73f04643d3dbcee3a445cc8c4278c8 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:43:45 -0500 Subject: [PATCH 020/282] add mock --- .../contract/src/MockInitializable.compact | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 contracts/initializable/contract/src/MockInitializable.compact diff --git a/contracts/initializable/contract/src/MockInitializable.compact b/contracts/initializable/contract/src/MockInitializable.compact new file mode 100644 index 00000000..d670f6d9 --- /dev/null +++ b/contracts/initializable/contract/src/MockInitializable.compact @@ -0,0 +1,14 @@ +pragma language_version >= 0.14.0; + +import CompactStandardLibrary; +import Initializable prefix Initializable_; + +export { Initializable_state, Initializable_STATE }; + +export circuit initialize(): [] { + return Initializable_initialize(); +} + +export circuit isInitialized(): Boolean { + return Initializable_isInitialized(); +} From 6c94cb1b1a3fb572a4d2f13362cd5f6bd2793c12 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:44:55 -0500 Subject: [PATCH 021/282] wrap contract logic in module --- .../contract/src/initializable.compact | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/contracts/initializable/contract/src/initializable.compact b/contracts/initializable/contract/src/initializable.compact index e5d9e8cb..01faf8cc 100644 --- a/contracts/initializable/contract/src/initializable.compact +++ b/contracts/initializable/contract/src/initializable.compact @@ -1,12 +1,32 @@ pragma language_version >= 0.14.0; -import CompactStandardLibrary; +/** + * @module Initializable + * @description Initializable provides a simple mechanism that mimics the functionality of a constructor. + */ +module Initializable{ + import CompactStandardLibrary; -export enum STATE { uninitialized, initialized } + export enum STATE { uninitialized, initialized } -export ledger state: STATE; + export ledger state: STATE; -export circuit initialize(): [] { - assert state == STATE.uninitialized "Contract already initialized"; - state = STATE.initialized; + /** + * @description Sets `STATE` to initialized thus ensuring the calling circuit can only be called once. + * + * @returns None. + */ + export circuit initialize(): [] { + assert state == STATE.uninitialized "Contract already initialized"; + state = STATE.initialized; + } + + /** + * @description Returns true if the state is initialized. + * + * @returns {Boolean} - whether the contract has been initialized. + */ + export circuit isInitialized(): Boolean { + return (state == STATE.initialized); + } } From de569706dcb7638c9d5151cdfbb0cab0f490dec2 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:45:37 -0500 Subject: [PATCH 022/282] add spdx --- contracts/initializable/contract/src/initializable.compact | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/initializable/contract/src/initializable.compact b/contracts/initializable/contract/src/initializable.compact index 01faf8cc..3b11cb15 100644 --- a/contracts/initializable/contract/src/initializable.compact +++ b/contracts/initializable/contract/src/initializable.compact @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma language_version >= 0.14.0; /** From b40c25dac0e382ee457f9737878711b9c7f97efc Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:46:46 -0500 Subject: [PATCH 023/282] fix simulator --- .../src/test/InitializableSimulator.ts | 80 +++++++++++++++++++ .../contract/src/test/initializable-setup.ts | 35 -------- 2 files changed, 80 insertions(+), 35 deletions(-) create mode 100644 contracts/initializable/contract/src/test/InitializableSimulator.ts delete mode 100644 contracts/initializable/contract/src/test/initializable-setup.ts diff --git a/contracts/initializable/contract/src/test/InitializableSimulator.ts b/contracts/initializable/contract/src/test/InitializableSimulator.ts new file mode 100644 index 00000000..9857fa59 --- /dev/null +++ b/contracts/initializable/contract/src/test/InitializableSimulator.ts @@ -0,0 +1,80 @@ +import { type CircuitContext, type ContractState, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; +import { Contract as MockInitializable, type Ledger, ledger } from '../artifacts/MockInitializable/contract/index.cjs'; +import type { IContractSimulator } from './types'; +import { InitializablePrivateState, InitializableWitnesses } from '../witnesses'; + +/** + * @description A simulator implementation of an utils contract for testing purposes. + * @template P - The private state type, fixed to UtilsPrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class InitializableSimulator + implements IContractSimulator +{ + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockInitializable; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor() { + this.contract = new MockInitializable( + InitializableWitnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)) + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type UtilsPrivateState. + */ + public getCurrentPrivateState(): InitializablePrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + + public initialize() { + this.circuitContext = this.contract.impureCircuits.initialize(this.circuitContext).context; + } + + public isInitialized(): boolean { + return this.contract.impureCircuits.isInitialized(this.circuitContext).result; + } +} diff --git a/contracts/initializable/contract/src/test/initializable-setup.ts b/contracts/initializable/contract/src/test/initializable-setup.ts deleted file mode 100644 index b0d9bf3e..00000000 --- a/contracts/initializable/contract/src/test/initializable-setup.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { type CircuitContext, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; -import { Contract, type Ledger, ledger } from '../artifacts/initializable/contract/index.cjs'; -import { type InitializablePrivateState, witnesses } from '../witnesses.js'; - -export class InitializableMock { - readonly contract: Contract; - circuitContext: CircuitContext; - - constructor() { - this.contract = new Contract(witnesses); - const { currentPrivateState, currentContractState, currentZswapLocalState } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)), - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext(currentContractState.data, sampleContractAddress()), - }; - } - - public getLedger(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - public getPrivateState(): InitializablePrivateState { - return this.circuitContext.currentPrivateState; - } - - public initialize(): Ledger { - // Update the current context to be the result of executing the circuit. - this.circuitContext = this.contract.impureCircuits.initialize(this.circuitContext).context; - return ledger(this.circuitContext.transactionContext.state); - } -} From b984849d7e429f6b0849b922c4a89ac0984a011d Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:47:12 -0500 Subject: [PATCH 024/282] clean up tests --- .../contract/src/test/initializable.test.ts | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/contracts/initializable/contract/src/test/initializable.test.ts b/contracts/initializable/contract/src/test/initializable.test.ts index 01ad03da..15ee059c 100644 --- a/contracts/initializable/contract/src/test/initializable.test.ts +++ b/contracts/initializable/contract/src/test/initializable.test.ts @@ -1,37 +1,32 @@ import { it, describe, expect } from '@jest/globals'; -import { InitializableMock } from './initializable-setup.js'; -import { NetworkId, setNetworkId } from '@midnight-ntwrk/midnight-js-network-id'; +import { InitializableSimulator } from './InitializableSimulator.js'; +import { Initializable_STATE as STATE } from '../artifacts/MockInitializable/contract/index.cjs'; -setNetworkId(NetworkId.Undeployed); - -const contract = new InitializableMock(); +const contract = new InitializableSimulator(); describe('Initializable', () => { - it('generates initial ledger state deterministically', () => { - const contract2 = new InitializableMock(); - expect(contract.getLedger()).toEqual(contract2.getLedger()); - }); - - it('properly initializes ledger state and private state', () => { - const initialLedgerState = contract.getLedger(); - expect(initialLedgerState.state).toEqual(0); + it('should generate the initial ledger state deterministically', () => { + const contract2 = new InitializableSimulator(); + expect(contract.getCurrentPublicState()).toEqual(contract2.getCurrentPublicState()); + }); - const initialPrivateState = contract.getPrivateState(); - expect(initialPrivateState).toEqual({}); + describe('initialize', () => { + it('should not be initialized', () => { + expect(contract.isInitialized()).toEqual(false); + expect(contract.getCurrentPublicState().initializableState).toEqual(STATE.uninitialized); }); - it('initializes the state correctly', () => { - const nextLedgerState = contract.initialize(); - expect(nextLedgerState.state).toEqual(1); - - const nextPrivateState = contract.getPrivateState(); - expect(nextPrivateState).toEqual({}); + it('should initialize', () => { + contract.initialize(); + expect(contract.isInitialized()).toEqual(true); + expect(contract.getCurrentPublicState().initializableState).toEqual(STATE.initialized); + }); }); - it('fails when re-initialized', () => { + it('should fail when re-initialized', () => { expect(() => { contract.initialize(); contract.initialize(); }).toThrow('Contract already initialized'); - }); }); +}); From 7ac436ffc626d4e1c5be6e72df46f85a0536b36d Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:47:45 -0500 Subject: [PATCH 025/282] add witnesses dir --- .../src/{witnesses.ts => witnesses/InitializableWitnesses.ts} | 3 +-- contracts/initializable/contract/src/witnesses/index.ts | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) rename contracts/initializable/contract/src/{witnesses.ts => witnesses/InitializableWitnesses.ts} (71%) create mode 100644 contracts/initializable/contract/src/witnesses/index.ts diff --git a/contracts/initializable/contract/src/witnesses.ts b/contracts/initializable/contract/src/witnesses/InitializableWitnesses.ts similarity index 71% rename from contracts/initializable/contract/src/witnesses.ts rename to contracts/initializable/contract/src/witnesses/InitializableWitnesses.ts index 297e4f19..9d99cd04 100644 --- a/contracts/initializable/contract/src/witnesses.ts +++ b/contracts/initializable/contract/src/witnesses/InitializableWitnesses.ts @@ -1,4 +1,3 @@ // This is how we type an empty object. export type InitializablePrivateState = Record; - -export const witnesses = {}; +export const InitializableWitnesses = {}; diff --git a/contracts/initializable/contract/src/witnesses/index.ts b/contracts/initializable/contract/src/witnesses/index.ts new file mode 100644 index 00000000..d27dd4c3 --- /dev/null +++ b/contracts/initializable/contract/src/witnesses/index.ts @@ -0,0 +1,2 @@ +export * from '../artifacts/initializable/contract/index.cjs'; +export * from './InitializableWitnesses'; From 9971accca2f75ca3653e4b9a2f1723778bd2c5ce Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:48:03 -0500 Subject: [PATCH 026/282] add testing pattern --- contracts/initializable/contract/src/index.ts | 2 - .../contract/src/test/types/index.ts | 1 + .../contract/src/test/types/test.ts | 23 +++++++ .../contract/src/test/utils/index.ts | 1 + .../contract/src/test/utils/test.ts | 67 +++++++++++++++++++ 5 files changed, 92 insertions(+), 2 deletions(-) delete mode 100644 contracts/initializable/contract/src/index.ts create mode 100644 contracts/initializable/contract/src/test/types/index.ts create mode 100644 contracts/initializable/contract/src/test/types/test.ts create mode 100644 contracts/initializable/contract/src/test/utils/index.ts create mode 100644 contracts/initializable/contract/src/test/utils/test.ts diff --git a/contracts/initializable/contract/src/index.ts b/contracts/initializable/contract/src/index.ts deleted file mode 100644 index d2e0a123..00000000 --- a/contracts/initializable/contract/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './artifacts/initializable/contract/index.cjs'; -export * from './witnesses.js'; diff --git a/contracts/initializable/contract/src/test/types/index.ts b/contracts/initializable/contract/src/test/types/index.ts new file mode 100644 index 00000000..db642b5e --- /dev/null +++ b/contracts/initializable/contract/src/test/types/index.ts @@ -0,0 +1 @@ +export type { IContractSimulator } from './test'; diff --git a/contracts/initializable/contract/src/test/types/test.ts b/contracts/initializable/contract/src/test/types/test.ts new file mode 100644 index 00000000..10fb6c98 --- /dev/null +++ b/contracts/initializable/contract/src/test/types/test.ts @@ -0,0 +1,23 @@ +import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; + +/** + * Generic interface for mock contract implementations. + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + */ +export interface IContractSimulator { + /** The contract's deployed address. */ + readonly contractAddress: string; + + /** The current circuit context. */ + circuitContext: CircuitContext

; + + /** Retrieves the current ledger state. */ + getCurrentPublicState(): L; + + /** Retrieves the current private state. */ + getCurrentPrivateState(): P; + + /** Retrieves the current contract state. */ + getCurrentContractState(): ContractState; +} diff --git a/contracts/initializable/contract/src/test/utils/index.ts b/contracts/initializable/contract/src/test/utils/index.ts new file mode 100644 index 00000000..14e02ef2 --- /dev/null +++ b/contracts/initializable/contract/src/test/utils/index.ts @@ -0,0 +1 @@ +export { useCircuitContext as circuitContext } from './test'; diff --git a/contracts/initializable/contract/src/test/utils/test.ts b/contracts/initializable/contract/src/test/utils/test.ts new file mode 100644 index 00000000..5a9e5837 --- /dev/null +++ b/contracts/initializable/contract/src/test/utils/test.ts @@ -0,0 +1,67 @@ +import { + type CircuitContext, + type CoinPublicKey, + type ContractAddress, + type ContractState, + QueryContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import type { IContractSimulator } from '../types'; + +/** + * Constructs a `CircuitContext` from the given state and sender information. + * + * This is typically used at runtime to provide the necessary context + * for executing circuits, including contract state, private state, + * sender identity, and transaction data. + * + * @template P - The type of the contract's private state. + * @param privateState - The current private state of the contract. + * @param contractState - The full contract state, including public and private data. + * @param sender - The public key of the sender (used in the circuit). + * @param contractAddress - The address of the deployed contract. + * @returns A fully populated `CircuitContext` for circuit execution. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContext

( + privateState: P, + contractState: ContractState, + sender: CoinPublicKey, + contractAddress: ContractAddress, +): CircuitContext

{ + return { + originalState: contractState, + currentPrivateState: privateState, + transactionContext: new QueryContext(contractState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} + +/** + * Prepares a new `CircuitContext` using the given sender and contract. + * + * Useful for mocking or updating the circuit context with a custom sender. + * + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + * @template C - The specific type of the contract implementing `MockContract`. + * @param contract - The contract instance implementing `MockContract`. + * @param sender - The public key to set as the sender in the new circuit context. + * @returns A new `CircuitContext` with the sender and updated context values. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContextSender>( + contract: C, + sender: CoinPublicKey, +): CircuitContext

{ + const currentPrivateState = contract.getCurrentPrivateState(); + const originalState = contract.getCurrentContractState(); + const contractAddress = contract.contractAddress; + + return { + originalState, + currentPrivateState, + transactionContext: new QueryContext(originalState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} From abf702713db474d8730156ead43b34777af43760 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:50:20 -0500 Subject: [PATCH 027/282] improve comments --- .../initializable/contract/src/initializable.compact | 2 +- .../contract/src/test/InitializableSimulator.ts | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/contracts/initializable/contract/src/initializable.compact b/contracts/initializable/contract/src/initializable.compact index 3b11cb15..648f7670 100644 --- a/contracts/initializable/contract/src/initializable.compact +++ b/contracts/initializable/contract/src/initializable.compact @@ -13,7 +13,7 @@ module Initializable{ export ledger state: STATE; /** - * @description Sets `STATE` to initialized thus ensuring the calling circuit can only be called once. + * @description Initializes the state thus ensuring the calling circuit can only be called once. * * @returns None. */ diff --git a/contracts/initializable/contract/src/test/InitializableSimulator.ts b/contracts/initializable/contract/src/test/InitializableSimulator.ts index 9857fa59..6778bfa0 100644 --- a/contracts/initializable/contract/src/test/InitializableSimulator.ts +++ b/contracts/initializable/contract/src/test/InitializableSimulator.ts @@ -70,10 +70,18 @@ export class InitializableSimulator return this.circuitContext.originalState; } + /** + * @description Initializes the state. + * @returns None. + */ public initialize() { this.circuitContext = this.contract.impureCircuits.initialize(this.circuitContext).context; } + /** + * @description Returns true if the state is initialized. + * @returns {boolean} - whether the contract has been initialized. + */ public isInitialized(): boolean { return this.contract.impureCircuits.isInitialized(this.circuitContext).result; } From ed3448b856fe2e2f0d429733bc578b06affd4ae3 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:52:00 -0500 Subject: [PATCH 028/282] tidy up simulator --- .../initializable/contract/src/test/InitializableSimulator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/initializable/contract/src/test/InitializableSimulator.ts b/contracts/initializable/contract/src/test/InitializableSimulator.ts index 6778bfa0..89402a19 100644 --- a/contracts/initializable/contract/src/test/InitializableSimulator.ts +++ b/contracts/initializable/contract/src/test/InitializableSimulator.ts @@ -80,7 +80,7 @@ export class InitializableSimulator /** * @description Returns true if the state is initialized. - * @returns {boolean} - whether the contract has been initialized. + * @returns Whether the contract has been initialized. */ public isInitialized(): boolean { return this.contract.impureCircuits.isInitialized(this.circuitContext).result; From 670600f9f53bbaf56ceadeda4f7a2c7b5af7632d Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 18:20:43 -0500 Subject: [PATCH 029/282] fix build contract script --- contracts/initializable/contract/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/initializable/contract/package.json b/contracts/initializable/contract/package.json index 10893d46..a04f1d3a 100644 --- a/contracts/initializable/contract/package.json +++ b/contracts/initializable/contract/package.json @@ -16,7 +16,7 @@ "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", "test": "NODE_OPTIONS=--experimental-vm-modules jest", "prepack": "yarn build", - "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/initializable.compact ./dist", + "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/Initializable.compact ./dist", "lint": "eslint src", "typecheck": "tsc -p tsconfig.json --noEmit" }, From dcd46585486ad882c26342803fb583ab607b1f34 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 5 Apr 2025 18:01:05 -0500 Subject: [PATCH 030/282] fix eslintignore --- contracts/erc721/contract/.eslintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/erc721/contract/.eslintignore b/contracts/erc721/contract/.eslintignore index 652df825..327555cd 100644 --- a/contracts/erc721/contract/.eslintignore +++ b/contracts/erc721/contract/.eslintignore @@ -1 +1 @@ -src/managed +src/artifacts From ddbc01d0877bfaaa34b5289f8c16bf0b7673a4cf Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 5 Apr 2025 18:10:09 -0500 Subject: [PATCH 031/282] add init module doc --- contracts/utils/contract/src/Utils.compact | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/utils/contract/src/Utils.compact b/contracts/utils/contract/src/Utils.compact index 26a9bc84..b9678d35 100644 --- a/contracts/utils/contract/src/Utils.compact +++ b/contracts/utils/contract/src/Utils.compact @@ -2,6 +2,10 @@ pragma language_version >= 0.14.0; +/** + * @module Utils. + * @description A library for common utilities used in Midnight contracts. + */ module Utils { import CompactStandardLibrary; From 8477f96b08b498bd6e53270c2e6253272b3cfec0 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 5 Apr 2025 18:11:11 -0500 Subject: [PATCH 032/282] fix description --- contracts/utils/contract/src/Utils.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/contract/src/Utils.compact b/contracts/utils/contract/src/Utils.compact index b9678d35..acb02784 100644 --- a/contracts/utils/contract/src/Utils.compact +++ b/contracts/utils/contract/src/Utils.compact @@ -4,7 +4,7 @@ pragma language_version >= 0.14.0; /** * @module Utils. - * @description A library for common utilities used in Midnight contracts. + * @description A library for common utilities used in Compact contracts. */ module Utils { import CompactStandardLibrary; From cb9c771eb1642c4da35e05a1a48caa94a46bce0b Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Sat, 5 Apr 2025 21:54:15 -0500 Subject: [PATCH 033/282] fix file name --- .../contract/src/{initializable.compact => Initializable.compact} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename contracts/initializable/contract/src/{initializable.compact => Initializable.compact} (100%) diff --git a/contracts/initializable/contract/src/initializable.compact b/contracts/initializable/contract/src/Initializable.compact similarity index 100% rename from contracts/initializable/contract/src/initializable.compact rename to contracts/initializable/contract/src/Initializable.compact From 540ea8415bc315d930342b658bcfe71f04268df0 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 7 Apr 2025 02:36:38 -0500 Subject: [PATCH 034/282] remove contract dir --- contracts/erc721/contract/jest.config.ts | 28 ----------------- contracts/erc721/contract/package.json | 29 ------------------ .../contract => initializable}/.eslintignore | 0 .../contract => initializable}/.eslintrc.cjs | 0 .../initializable/contract/.eslintignore | 1 - .../initializable/contract/.eslintrc.cjs | 30 ------------------- .../initializable/contract/js-resolver.cjs | 16 ---------- .../contract/tsconfig.build.json | 5 ---- .../initializable/contract/tsconfig.json | 21 ------------- .../{contract => }/jest.config.ts | 0 .../js-resolver.cjs | 0 .../initializable/{contract => }/package.json | 0 .../{contract => }/src/Initializable.compact | 0 .../src/MockInitializable.compact | 0 .../src/test/InitializableSimulator.ts | 0 .../src/test/initializable.test.ts | 0 .../{contract => }/src/test/types/index.ts | 0 .../{contract => }/src/test/types/test.ts | 0 .../{contract => }/src/test/utils/index.ts | 0 .../{contract => }/src/test/utils/test.ts | 0 .../src/witnesses/InitializableWitnesses.ts | 0 .../{contract => }/src/witnesses/index.ts | 0 .../tsconfig.build.json | 0 .../contract => initializable}/tsconfig.json | 0 .../{contract => }/src/MockUtils.compact | 0 .../utils/{contract => }/src/Utils.compact | 0 .../{contract => }/src/test/UtilsSimulator.ts | 0 .../{contract => }/src/test/types/index.ts | 0 .../{contract => }/src/test/types/test.ts | 0 .../{contract => }/src/test/utils.test.ts | 0 .../{contract => }/src/test/utils/address.ts | 0 .../{contract => }/src/test/utils/index.ts | 0 .../{contract => }/src/test/utils/test.ts | 0 .../src/witnesses/UtilsWitnesses.ts | 0 .../{contract => }/src/witnesses/index.ts | 0 yarn.lock | 6 ++-- 36 files changed, 3 insertions(+), 133 deletions(-) delete mode 100644 contracts/erc721/contract/jest.config.ts delete mode 100644 contracts/erc721/contract/package.json rename contracts/{erc721/contract => initializable}/.eslintignore (100%) rename contracts/{erc721/contract => initializable}/.eslintrc.cjs (100%) delete mode 100644 contracts/initializable/contract/.eslintignore delete mode 100644 contracts/initializable/contract/.eslintrc.cjs delete mode 100644 contracts/initializable/contract/js-resolver.cjs delete mode 100644 contracts/initializable/contract/tsconfig.build.json delete mode 100644 contracts/initializable/contract/tsconfig.json rename contracts/initializable/{contract => }/jest.config.ts (100%) rename contracts/{erc721/contract => initializable}/js-resolver.cjs (100%) rename contracts/initializable/{contract => }/package.json (100%) rename contracts/initializable/{contract => }/src/Initializable.compact (100%) rename contracts/initializable/{contract => }/src/MockInitializable.compact (100%) rename contracts/initializable/{contract => }/src/test/InitializableSimulator.ts (100%) rename contracts/initializable/{contract => }/src/test/initializable.test.ts (100%) rename contracts/initializable/{contract => }/src/test/types/index.ts (100%) rename contracts/initializable/{contract => }/src/test/types/test.ts (100%) rename contracts/initializable/{contract => }/src/test/utils/index.ts (100%) rename contracts/initializable/{contract => }/src/test/utils/test.ts (100%) rename contracts/initializable/{contract => }/src/witnesses/InitializableWitnesses.ts (100%) rename contracts/initializable/{contract => }/src/witnesses/index.ts (100%) rename contracts/{erc721/contract => initializable}/tsconfig.build.json (100%) rename contracts/{erc721/contract => initializable}/tsconfig.json (100%) rename contracts/utils/{contract => }/src/MockUtils.compact (100%) rename contracts/utils/{contract => }/src/Utils.compact (100%) rename contracts/utils/{contract => }/src/test/UtilsSimulator.ts (100%) rename contracts/utils/{contract => }/src/test/types/index.ts (100%) rename contracts/utils/{contract => }/src/test/types/test.ts (100%) rename contracts/utils/{contract => }/src/test/utils.test.ts (100%) rename contracts/utils/{contract => }/src/test/utils/address.ts (100%) rename contracts/utils/{contract => }/src/test/utils/index.ts (100%) rename contracts/utils/{contract => }/src/test/utils/test.ts (100%) rename contracts/utils/{contract => }/src/witnesses/UtilsWitnesses.ts (100%) rename contracts/utils/{contract => }/src/witnesses/index.ts (100%) diff --git a/contracts/erc721/contract/jest.config.ts b/contracts/erc721/contract/jest.config.ts deleted file mode 100644 index edbdaeba..00000000 --- a/contracts/erc721/contract/jest.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Config } from "@jest/types"; - -const config: Config.InitialOptions = { - preset: "ts-jest/presets/default-esm", - testEnvironment: "node", - verbose: true, - roots: [""], - modulePaths: [""], - passWithNoTests: false, - testMatch: ["**/*.test.ts"], - extensionsToTreatAsEsm: [".ts"], - collectCoverage: true, - resolver: '/js-resolver.cjs', - coverageThreshold: { - global: { - //branches: 60, - //functions: 75, - //lines: 70, - }, - }, - reporters: [ - "default", - ["jest-junit", { outputDirectory: "reports", outputName: "report.xml" }], - ["jest-html-reporters", { publicPath: "reports", filename: "report.html" }], - ], -}; - -export default config; diff --git a/contracts/erc721/contract/package.json b/contracts/erc721/contract/package.json deleted file mode 100644 index 01eeea4e..00000000 --- a/contracts/erc721/contract/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "@openzeppelin-midnight-contracts/erc721-contract", - "type": "module", - "main": "dist/index.js", - "module": "dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "require": "./dist/index.js", - "import": "./dist/index.js", - "default": "./dist/index.js" - } - }, - "scripts": { - "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", - "test": "NODE_OPTIONS=--experimental-vm-modules jest", - "prepack": "yarn build", - "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/erc721.compact ./dist", - "lint": "eslint src", - "typecheck": "tsc -p tsconfig.json --noEmit" - }, - "devDependencies": { - "@midnight-ntwrk/compact": "workspace:*", - "eslint": "^8.52.0", - "jest": "^29.7.0", - "typescript": "^5.2.2" - } -} diff --git a/contracts/erc721/contract/.eslintignore b/contracts/initializable/.eslintignore similarity index 100% rename from contracts/erc721/contract/.eslintignore rename to contracts/initializable/.eslintignore diff --git a/contracts/erc721/contract/.eslintrc.cjs b/contracts/initializable/.eslintrc.cjs similarity index 100% rename from contracts/erc721/contract/.eslintrc.cjs rename to contracts/initializable/.eslintrc.cjs diff --git a/contracts/initializable/contract/.eslintignore b/contracts/initializable/contract/.eslintignore deleted file mode 100644 index 327555cd..00000000 --- a/contracts/initializable/contract/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -src/artifacts diff --git a/contracts/initializable/contract/.eslintrc.cjs b/contracts/initializable/contract/.eslintrc.cjs deleted file mode 100644 index 581f1d49..00000000 --- a/contracts/initializable/contract/.eslintrc.cjs +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - node: true, - jest: true, - }, - extends: [ - 'standard-with-typescript', - 'plugin:prettier/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - overrides: [], - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['tsconfig.json'], - }, - rules: { - '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 - '@typescript-eslint/no-floating-promises': 'warn', - '@typescript-eslint/promise-function-async': 'off', - '@typescript-eslint/no-redeclare': 'off', - '@typescript-eslint/no-invalid-void-type': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/consistent-type-definitions': 'off' - }, -}; diff --git a/contracts/initializable/contract/js-resolver.cjs b/contracts/initializable/contract/js-resolver.cjs deleted file mode 100644 index cc9ed285..00000000 --- a/contracts/initializable/contract/js-resolver.cjs +++ /dev/null @@ -1,16 +0,0 @@ -const jsResolver = (path, options) => { - const jsExtRegex = /\.js$/i - const resolver = options.defaultResolver - if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { - const newPath = path.replace(jsExtRegex, '.ts'); - try { - return resolver(newPath, options) - } catch { - // use default resolver - } - } - - return resolver(path, options) -} - -module.exports = jsResolver diff --git a/contracts/initializable/contract/tsconfig.build.json b/contracts/initializable/contract/tsconfig.build.json deleted file mode 100644 index f1132509..00000000 --- a/contracts/initializable/contract/tsconfig.build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["src/test/**/*.ts"], - "compilerOptions": {} -} diff --git a/contracts/initializable/contract/tsconfig.json b/contracts/initializable/contract/tsconfig.json deleted file mode 100644 index 3e90b0a9..00000000 --- a/contracts/initializable/contract/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "include": ["src/**/*.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - "declaration": true, - "lib": ["ESNext"], - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "node", - "allowJs": true, - "forceConsistentCasingInFileNames": true, - "noImplicitAny": true, - "strict": true, - "isolatedModules": true, - "sourceMap": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "skipLibCheck": true - } -} diff --git a/contracts/initializable/contract/jest.config.ts b/contracts/initializable/jest.config.ts similarity index 100% rename from contracts/initializable/contract/jest.config.ts rename to contracts/initializable/jest.config.ts diff --git a/contracts/erc721/contract/js-resolver.cjs b/contracts/initializable/js-resolver.cjs similarity index 100% rename from contracts/erc721/contract/js-resolver.cjs rename to contracts/initializable/js-resolver.cjs diff --git a/contracts/initializable/contract/package.json b/contracts/initializable/package.json similarity index 100% rename from contracts/initializable/contract/package.json rename to contracts/initializable/package.json diff --git a/contracts/initializable/contract/src/Initializable.compact b/contracts/initializable/src/Initializable.compact similarity index 100% rename from contracts/initializable/contract/src/Initializable.compact rename to contracts/initializable/src/Initializable.compact diff --git a/contracts/initializable/contract/src/MockInitializable.compact b/contracts/initializable/src/MockInitializable.compact similarity index 100% rename from contracts/initializable/contract/src/MockInitializable.compact rename to contracts/initializable/src/MockInitializable.compact diff --git a/contracts/initializable/contract/src/test/InitializableSimulator.ts b/contracts/initializable/src/test/InitializableSimulator.ts similarity index 100% rename from contracts/initializable/contract/src/test/InitializableSimulator.ts rename to contracts/initializable/src/test/InitializableSimulator.ts diff --git a/contracts/initializable/contract/src/test/initializable.test.ts b/contracts/initializable/src/test/initializable.test.ts similarity index 100% rename from contracts/initializable/contract/src/test/initializable.test.ts rename to contracts/initializable/src/test/initializable.test.ts diff --git a/contracts/initializable/contract/src/test/types/index.ts b/contracts/initializable/src/test/types/index.ts similarity index 100% rename from contracts/initializable/contract/src/test/types/index.ts rename to contracts/initializable/src/test/types/index.ts diff --git a/contracts/initializable/contract/src/test/types/test.ts b/contracts/initializable/src/test/types/test.ts similarity index 100% rename from contracts/initializable/contract/src/test/types/test.ts rename to contracts/initializable/src/test/types/test.ts diff --git a/contracts/initializable/contract/src/test/utils/index.ts b/contracts/initializable/src/test/utils/index.ts similarity index 100% rename from contracts/initializable/contract/src/test/utils/index.ts rename to contracts/initializable/src/test/utils/index.ts diff --git a/contracts/initializable/contract/src/test/utils/test.ts b/contracts/initializable/src/test/utils/test.ts similarity index 100% rename from contracts/initializable/contract/src/test/utils/test.ts rename to contracts/initializable/src/test/utils/test.ts diff --git a/contracts/initializable/contract/src/witnesses/InitializableWitnesses.ts b/contracts/initializable/src/witnesses/InitializableWitnesses.ts similarity index 100% rename from contracts/initializable/contract/src/witnesses/InitializableWitnesses.ts rename to contracts/initializable/src/witnesses/InitializableWitnesses.ts diff --git a/contracts/initializable/contract/src/witnesses/index.ts b/contracts/initializable/src/witnesses/index.ts similarity index 100% rename from contracts/initializable/contract/src/witnesses/index.ts rename to contracts/initializable/src/witnesses/index.ts diff --git a/contracts/erc721/contract/tsconfig.build.json b/contracts/initializable/tsconfig.build.json similarity index 100% rename from contracts/erc721/contract/tsconfig.build.json rename to contracts/initializable/tsconfig.build.json diff --git a/contracts/erc721/contract/tsconfig.json b/contracts/initializable/tsconfig.json similarity index 100% rename from contracts/erc721/contract/tsconfig.json rename to contracts/initializable/tsconfig.json diff --git a/contracts/utils/contract/src/MockUtils.compact b/contracts/utils/src/MockUtils.compact similarity index 100% rename from contracts/utils/contract/src/MockUtils.compact rename to contracts/utils/src/MockUtils.compact diff --git a/contracts/utils/contract/src/Utils.compact b/contracts/utils/src/Utils.compact similarity index 100% rename from contracts/utils/contract/src/Utils.compact rename to contracts/utils/src/Utils.compact diff --git a/contracts/utils/contract/src/test/UtilsSimulator.ts b/contracts/utils/src/test/UtilsSimulator.ts similarity index 100% rename from contracts/utils/contract/src/test/UtilsSimulator.ts rename to contracts/utils/src/test/UtilsSimulator.ts diff --git a/contracts/utils/contract/src/test/types/index.ts b/contracts/utils/src/test/types/index.ts similarity index 100% rename from contracts/utils/contract/src/test/types/index.ts rename to contracts/utils/src/test/types/index.ts diff --git a/contracts/utils/contract/src/test/types/test.ts b/contracts/utils/src/test/types/test.ts similarity index 100% rename from contracts/utils/contract/src/test/types/test.ts rename to contracts/utils/src/test/types/test.ts diff --git a/contracts/utils/contract/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts similarity index 100% rename from contracts/utils/contract/src/test/utils.test.ts rename to contracts/utils/src/test/utils.test.ts diff --git a/contracts/utils/contract/src/test/utils/address.ts b/contracts/utils/src/test/utils/address.ts similarity index 100% rename from contracts/utils/contract/src/test/utils/address.ts rename to contracts/utils/src/test/utils/address.ts diff --git a/contracts/utils/contract/src/test/utils/index.ts b/contracts/utils/src/test/utils/index.ts similarity index 100% rename from contracts/utils/contract/src/test/utils/index.ts rename to contracts/utils/src/test/utils/index.ts diff --git a/contracts/utils/contract/src/test/utils/test.ts b/contracts/utils/src/test/utils/test.ts similarity index 100% rename from contracts/utils/contract/src/test/utils/test.ts rename to contracts/utils/src/test/utils/test.ts diff --git a/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts b/contracts/utils/src/witnesses/UtilsWitnesses.ts similarity index 100% rename from contracts/utils/contract/src/witnesses/UtilsWitnesses.ts rename to contracts/utils/src/witnesses/UtilsWitnesses.ts diff --git a/contracts/utils/contract/src/witnesses/index.ts b/contracts/utils/src/witnesses/index.ts similarity index 100% rename from contracts/utils/contract/src/witnesses/index.ts rename to contracts/utils/src/witnesses/index.ts diff --git a/yarn.lock b/yarn.lock index 378e2992..f83eef79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1110,7 +1110,7 @@ __metadata: "@openzeppelin-midnight-contracts/initializable-contract@workspace:contracts/initializable/contract": version: 0.0.0-use.local - resolution: "@openzeppelin-midnight-contracts/initializable-contract@workspace:contracts/initializable/contract" + resolution: "@openzeppelin-midnight-contracts/initializable-contract@workspace:contracts/initializable" dependencies: "@midnight-ntwrk/compact": "workspace:*" eslint: "npm:^8.52.0" @@ -1119,9 +1119,9 @@ __metadata: languageName: unknown linkType: soft -"@openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils/contract": +"@openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils": version: 0.0.0-use.local - resolution: "@openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils/contract" + resolution: "@openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils" dependencies: "@midnight-ntwrk/compact": "workspace:*" eslint: "npm:^8.52.0" From e55f9024cbb7dfd824d3b821f1074ab25fc820c8 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 7 Apr 2025 02:56:09 -0500 Subject: [PATCH 035/282] re-add erc20 --- contracts/erc20/.eslintignore | 1 + contracts/erc20/.eslintrc.cjs | 30 ++ contracts/erc20/jest.config.ts | 28 ++ contracts/erc20/js-resolver.cjs | 16 + contracts/erc20/package.json | 29 ++ contracts/erc20/src/ERC20.compact | 341 ++++++++++++++++++ .../erc20/src/test/mocks/MockERC20.compact | 110 ++++++ .../src/test/simulators/ERC20Simulator.ts | 308 ++++++++++++++++ contracts/erc20/src/test/simulators/index.ts | 1 + contracts/erc20/src/test/types/index.ts | 6 + contracts/erc20/src/test/types/test.ts | 23 ++ contracts/erc20/src/test/utils/address.ts | 78 ++++ contracts/erc20/src/test/utils/index.ts | 2 + contracts/erc20/src/test/utils/test.ts | 67 ++++ .../erc20/src/witnesses/ERC20Witnesses.ts | 3 + contracts/erc20/src/witnesses/index.ts | 2 + contracts/erc20/tsconfig.build.json | 5 + contracts/erc20/tsconfig.json | 21 ++ package.json | 7 +- 19 files changed, 1074 insertions(+), 4 deletions(-) create mode 100644 contracts/erc20/.eslintignore create mode 100644 contracts/erc20/.eslintrc.cjs create mode 100644 contracts/erc20/jest.config.ts create mode 100644 contracts/erc20/js-resolver.cjs create mode 100644 contracts/erc20/package.json create mode 100644 contracts/erc20/src/ERC20.compact create mode 100644 contracts/erc20/src/test/mocks/MockERC20.compact create mode 100644 contracts/erc20/src/test/simulators/ERC20Simulator.ts create mode 100644 contracts/erc20/src/test/simulators/index.ts create mode 100644 contracts/erc20/src/test/types/index.ts create mode 100644 contracts/erc20/src/test/types/test.ts create mode 100644 contracts/erc20/src/test/utils/address.ts create mode 100644 contracts/erc20/src/test/utils/index.ts create mode 100644 contracts/erc20/src/test/utils/test.ts create mode 100644 contracts/erc20/src/witnesses/ERC20Witnesses.ts create mode 100644 contracts/erc20/src/witnesses/index.ts create mode 100644 contracts/erc20/tsconfig.build.json create mode 100644 contracts/erc20/tsconfig.json diff --git a/contracts/erc20/.eslintignore b/contracts/erc20/.eslintignore new file mode 100644 index 00000000..327555cd --- /dev/null +++ b/contracts/erc20/.eslintignore @@ -0,0 +1 @@ +src/artifacts diff --git a/contracts/erc20/.eslintrc.cjs b/contracts/erc20/.eslintrc.cjs new file mode 100644 index 00000000..581f1d49 --- /dev/null +++ b/contracts/erc20/.eslintrc.cjs @@ -0,0 +1,30 @@ +module.exports = { + env: { + browser: true, + es2021: true, + node: true, + jest: true, + }, + extends: [ + 'standard-with-typescript', + 'plugin:prettier/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + ], + overrides: [], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['tsconfig.json'], + }, + rules: { + '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 + '@typescript-eslint/no-floating-promises': 'warn', + '@typescript-eslint/promise-function-async': 'off', + '@typescript-eslint/no-redeclare': 'off', + '@typescript-eslint/no-invalid-void-type': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/consistent-type-definitions': 'off' + }, +}; diff --git a/contracts/erc20/jest.config.ts b/contracts/erc20/jest.config.ts new file mode 100644 index 00000000..3cbccc1b --- /dev/null +++ b/contracts/erc20/jest.config.ts @@ -0,0 +1,28 @@ +import type { Config } from "@jest/types"; + +const config: Config.InitialOptions = { + preset: "ts-jest/presets/default-esm", + testEnvironment: "node", + verbose: true, + roots: [""], + modulePaths: [""], + passWithNoTests: false, + testMatch: ["**/*.test.ts"], + extensionsToTreatAsEsm: [".ts"], + collectCoverage: true, + resolver: '/js-resolver.cjs', + coverageThreshold: { + global: { + branches: 50, + functions: 50, + lines: 50, + }, + }, + reporters: [ + "default", + ["jest-junit", { outputDirectory: "reports", outputName: "report.xml" }], + ["jest-html-reporters", { publicPath: "reports", filename: "report.html" }], + ], +}; + +export default config; diff --git a/contracts/erc20/js-resolver.cjs b/contracts/erc20/js-resolver.cjs new file mode 100644 index 00000000..cc9ed285 --- /dev/null +++ b/contracts/erc20/js-resolver.cjs @@ -0,0 +1,16 @@ +const jsResolver = (path, options) => { + const jsExtRegex = /\.js$/i + const resolver = options.defaultResolver + if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { + const newPath = path.replace(jsExtRegex, '.ts'); + try { + return resolver(newPath, options) + } catch { + // use default resolver + } + } + + return resolver(path, options) +} + +module.exports = jsResolver diff --git a/contracts/erc20/package.json b/contracts/erc20/package.json new file mode 100644 index 00000000..345721eb --- /dev/null +++ b/contracts/erc20/package.json @@ -0,0 +1,29 @@ +{ + "name": "@openzeppelin-midnight-contracts/erc20-contract", + "type": "module", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "scripts": { + "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", + "test": "NODE_OPTIONS=--experimental-vm-modules jest", + "prepack": "yarn build", + "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/ERC20.compact ./dist", + "lint": "eslint src", + "typecheck": "tsc -p tsconfig.json --noEmit" + }, + "devDependencies": { + "@midnight-ntwrk/compact": "workspace:*", + "eslint": "^8.52.0", + "jest": "^29.7.0", + "typescript": "^5.2.2" + } +} diff --git a/contracts/erc20/src/ERC20.compact b/contracts/erc20/src/ERC20.compact new file mode 100644 index 00000000..861ca5e9 --- /dev/null +++ b/contracts/erc20/src/ERC20.compact @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.14.0; + +/** + * @module ERC20 + * @description An unshielded ERC20 library. + * + * @notice One notable difference regarding this implementation and the EIP20 spec + * consists of the token size. Uint<128> is used as the token size because Uint<256> + * cannot be supported. + * This is due to encoding limits on the midnight circuit backend: + * https://github.com/midnightntwrk/compactc/issues/929 + * + * @notice Further discussion and consideration required: + * + * - Consider changing the underscore in the internal methods to `unsafe` or + * adopting dot notation for prefixing imports. + * - Revise logic once contract-to-contract interactions are available on midnight. + * - Consider implementing an introspection mechanism for transfers to contracts. + * - Standardize which zero address to use (`ZswapCoinPublicKey` or `ContractAddress`). + */ +module ERC20 { + import CompactStandardLibrary; + + /// Public state + export ledger _name: Maybe>; + export ledger _symbol: Maybe>; + export ledger _decimals: Uint<8>; + export ledger _totalSupply: Uint<128>; + export ledger _balances: Map, Uint<128>>; + export ledger _allowances: Map, Map, Uint<128>>>; + + /** + * @description Initializes the contract by setting the name, symbol, and decimals. + * + * @param name_ - The name of the token. + * @param symbol_ - The symbol of the token. + * @param decimals_ - The number of decimals used to get the user representation. + */ + export circuit initializer( + name_: Maybe>, + symbol_: Maybe>, + decimals_:Uint<8> + ): [] { + _name = name_; + _symbol = symbol_; + _decimals = decimals_; + } + + /** + * @description Returns the token name. + * + * @return {Maybe>} - The token name. + */ + export circuit name(): Maybe> { + return _name; + } + + /** + * @description Returns the symbol of the token. + * + * @return {Maybe>} - The token name. + */ + export circuit symbol(): Maybe> { + return _symbol; + } + + /** + * @description Returns the number of decimals used to get its user representation. + * + * @return {Uint<8>} - The account's token balance. + */ + export circuit decimals(): Uint<8> { + return _decimals; + } + + /** + * @description Returns the value of tokens in existence. + * + * @return {Uint<128>} - The total supply of tokens. + */ + export circuit totalSupply(): Uint<128> { + return _totalSupply; + } + + /** + * @description Returns the value of tokens owned by `account`. + * + * @dev Manually checks if `account` is a key in the map and returns 0 if it is not. + * + * @param {account} - The public key or contract address to query. + * @return {Uint<128>} - The account's token balance. + */ + export circuit balanceOf(account: Either): Uint<128> { + if (!_balances.member(account)) { + return 0; + } + + return _balances.lookup(account); + } + + /** + * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` + * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. + * + * @dev Manually checks if `owner` and `spender` are keys in the map and returns 0 if they are not. + * + * @param {owner} - The public key or contract address of approver. + * @param {spender} - The public key or contract address of spender. + * @return {Uint<128>} - The `spender`'s allowance over `owner`'s tokens. + */ + export circuit allowance( + owner: Either, + spender: Either + ): Uint<128> { + if (!_allowances.member(owner) || !_allowances.lookup(owner).member(spender)) { + return 0; + } + + return _allowances.lookup(owner).lookup(spender); + } + + /** + * @description Moves a `value` amount of tokens from the caller's account to `to`. + * + * @dev We need to get the caller address from contracts and handle the transfer appropriately. + * This should include a callback to ensure the contract can safely receive tokens. + * + * @param {to} - The recipient of the transfer, either a user or a contract. + * @param {value} - The amount to transfer. + * @return {Boolean} - As per the IERC20 spec, this MUST return true. + */ + export circuit transfer(to: Either, value: Uint<128>): Boolean { + // TMP - Waiting for contract-to-contract calls to handle `right` with contract address + const owner = left(own_public_key()); + _transfer(owner, to, value); + return true; + } + + /** + * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. + * `value` is the deducted from the caller's allowance. + * + * @dev We need to get the caller address from contracts and handle the transfer appropriately. + * This should include a callback to ensure the contract can safely receive tokens. + * + * @param {from} - The current owner of the tokens for the transfer, either a user or a contract. + * @param {to} - The recipient of the transfer, either a user or a contract. + * @param {value} - The amount to transfer. + * @return {Boolean} - As per the IERC20 spec, this MUST return true. + */ + export circuit transferFrom( + from: Either, + to: Either, + value: Uint<128> + ): Boolean { + // TMP - Waiting for contract-to-contract calls to handle `right` with contract address + const spender = left(own_public_key()); + _spendAllowance(from, spender, value); + _transfer(from, to, value); + return true; + } + + /** + * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. + * + * @param {spender} - The Zswap key or ContractAddress that may spend on behalf of the caller. + * @param {value} - The amount of tokens the `spender` may spend. + * @return {Boolean} - Returns a boolean value indicating whether the operation succeeded. + */ + export circuit approve(spender: Either, value: Uint<128>): Boolean { + // TMP - Waiting for contract-to-contract calls to handle `right` with contract address + const owner = left(own_public_key()); + _approve(owner, spender, value); + return true; + } + + /** + * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * @param {owner} - The owner of the tokens. + * @param {spender} - The spender of the tokens. + * @param {value} - The amount of tokens `spender` may spend on behalf of `owner`. + * @return {[]} - None. + */ + export circuit _approve( + owner: Either, + spender: Either, + value: Uint<128> + ): [] { + assert !isZero(owner) "ERC20: invalid owner"; + assert !isZero(spender) "ERC20: invalid spender"; + if (!_allowances.member(owner)) { + // If owner doesn't exist, create and insert a new sub-map directly + _allowances.insert(owner, default, Uint<128>>>); + } + _allowances.lookup(owner).insert(spender, value); + } + + /** + * @description Moves a `value` amount of tokens from `from` to `to`. + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * @param {from} - The owner of the tokens to transfer. + * @param {to} - The receipient of the transferred tokens. + * @param {value} - The amount of tokens to transfer. + * @return {[]} - None. + */ + export circuit _transfer( + from: Either, + to: Either, + value: Uint<128> + ): [] { + assert !isZero(from) "ERC20: invalid sender"; + assert !isZero(to) "ERC20: invalid receiver"; + + _update(from, to, value); + } + + /** + * @description Creates a `value` amount of tokens and assigns them to `account`, + * by transferring it from the zero address. Relies on the `update` mechanism. + * + * @param {account} - The recipient of tokens minted. + * @param {value} - The amount of tokens minted. + * @return {[]} - None. + */ + export circuit _mint( + account: Either, + value: Uint<128> + ): [] { + assert !isZero(account) "ERC20: invalid receiver"; + // Using the contract variant of 0 + // TODO: Look into if this matters + const zero_address = right(ContractAddress{ pad(32, "") }); + + _update(zero_address, account, value); + } + + /** + * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. + * Relies on the `_update` mechanism. + * + * @param {account} - The target owner of tokens to burn. + * @param {value} - The amount of tokens to burn. + * @return {[]} - None. + */ + export circuit _burn( + account: Either, + value: Uint<128> + ): [] { + assert !isZero(account) "ERC20: invalid sender"; + // Using the contract variant of 0 + // TODO: Look into if this matters + const zero_address = right(ContractAddress{ pad(32, "") }); + _update(account, zero_address, value); + } + + /** + * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` + * (or `to`) is the zero address. + * @dev Checks for a mint overflow in order to output a more readable error message. + * + * @param {from} - The original owner of the tokens moved (which is 0 if tokens are minted). + * @param {to} - The recipient of the tokens moved (which is 0 if tokens are burned). + * @param {value} - The amount of tokens moved from `from` to `to`. + * @return {[]} - None. + */ + export circuit _update( + from: Either, + to: Either, + value: Uint<128> + ): [] { + if (isZero(from)) { + // Mint + const MAX_UINT128 = 340282366920938463463374607431768211455; + assert MAX_UINT128 - _totalSupply >= value "ERC20: arithmetic overflow"; + + _totalSupply = _totalSupply + value as Uint<128>; + } else { + const fromBal = balanceOf(from); + assert fromBal >= value "ERC20: insufficient balance"; + _balances.insert(from, fromBal - value as Uint<128>); + } + + if (isZero(to)) { + // Burn + _totalSupply = _totalSupply - value as Uint<128>; + } else { + const toBal = balanceOf(to); + _balances.insert(to, toBal + value as Uint<128>); + } + } + + /** + * @description Updates `owner`'s allowance for `spender` based on spent `value`. + * Does not update the allowance value in case of infinite allowance. + * + * @param {owner} - The owner of the tokens. + * @param {spender} - The spender of the tokens. + * @param {value} - The amount of token allowance to spend. + * @return {[]} - None. + */ + export circuit _spendAllowance( + owner: Either, + spender: Either, + value: Uint<128> + ): [] { + // TODO: Look into improving design so we're not checking allowance member twice (here and in `_approve`) + assert (_allowances.member(owner) && _allowances.lookup(owner).member(spender)) "ERC20: insufficient allowance"; + + const currentAllowance = _allowances.lookup(owner).lookup(spender); + // TODO: improve readability of max_u128 + const MAX_UINT128 = 340282366920938463463374607431768211455; + if (currentAllowance < MAX_UINT128) { + assert currentAllowance >= value "ERC20: insufficient allowance"; + _approve(owner, spender, currentAllowance - value as Uint<128>); + } + } + + /** + * @description Returns whether `keyOrAddress` is the zero address. + * @todo Move to a utils contract since this will likely be reused. + * + * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @return {Boolean} - Returns true if `keyOrAddress` is zero. + */ + export pure circuit isZero(keyOrAddress: Either): Boolean { + const zero = pad(32, ""); + + if (keyOrAddress.is_left) { + return keyOrAddress == left(ZswapCoinPublicKey{ zero }); + } else { + return keyOrAddress == right(ContractAddress{ zero }); + } + } +} diff --git a/contracts/erc20/src/test/mocks/MockERC20.compact b/contracts/erc20/src/test/mocks/MockERC20.compact new file mode 100644 index 00000000..13750b72 --- /dev/null +++ b/contracts/erc20/src/test/mocks/MockERC20.compact @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.14.0; + +import CompactStandardLibrary; + +import "../../ERC20" prefix ERC20_; + +export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; + +constructor( + _name: Maybe>, + _symbol: Maybe>, + _decimals:Uint<8> +) { + ERC20_initializer(_name, _symbol, _decimals); +} + +export circuit name(): Maybe> { + return ERC20_name(); +} + +export circuit symbol(): Maybe> { + return ERC20_symbol(); +} + +export circuit decimals(): Uint<8> { + return ERC20_decimals(); +} + +export circuit totalSupply(): Uint<128> { + return ERC20_totalSupply(); +} + +export circuit balanceOf(account: Either): Uint<128> { + return ERC20_balanceOf(account); +} + +export circuit allowance( + owner: Either, + spender: Either +): Uint<128> { + return ERC20_allowance(owner, spender); +} + +export circuit transfer(to: Either, value: Uint<128>): Boolean { + return ERC20_transfer(to, value); +} + +export circuit transferFrom( + from: Either, + to: Either, + value: Uint<128> +): Boolean { + return ERC20_transferFrom(from, to, value); +} + +export circuit approve(spender: Either, value: Uint<128>): Boolean { + return ERC20_approve(spender, value); +} + +export circuit _approve( + owner: Either, + spender: Either, + value: Uint<128> +): [] { + return ERC20__approve(owner, spender, value); +} + +export circuit _transfer( + from: Either, + to: Either, + value: Uint<128> +): [] { + return ERC20__transfer(from, to, value); +} + +export circuit _mint( + account: Either, + value: Uint<128> +): [] { + return ERC20__mint(account, value); +} + +export circuit _burn( + account: Either, + value: Uint<128> +): [] { + return ERC20__burn(account, value); +} + +export circuit _update( + from: Either, + to: Either, + value: Uint<128> +): [] { + return ERC20__update(from, to, value); +} + +export circuit _spendAllowance( + owner: Either, + spender: Either, + value: Uint<128> +): [] { + return ERC20__spendAllowance(owner, spender, value); +} + +export pure circuit isZero(keyOrAddress: Either): Boolean { + return ERC20_isZero(keyOrAddress); +} \ No newline at end of file diff --git a/contracts/erc20/src/test/simulators/ERC20Simulator.ts b/contracts/erc20/src/test/simulators/ERC20Simulator.ts new file mode 100644 index 00000000..d4b0fb6e --- /dev/null +++ b/contracts/erc20/src/test/simulators/ERC20Simulator.ts @@ -0,0 +1,308 @@ +import { + type CircuitContext, + CoinPublicKey, + type ContractState, + QueryContext, + constructorContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import { sampleContractAddress } from '@midnight-ntwrk/zswap'; +import { + type Ledger, + Contract as MockERC20, + ledger, + Either, + ZswapCoinPublicKey, + ContractAddress, +} from '../../artifacts/MockERC20/contract/index.cjs'; // Combined imports +import { MaybeString } from '../types'; +import type { IContractSimulator } from './../types'; +import { ERC20PrivateState, ERC20Witnesses } from '../../witnesses'; + +/** + * @description A simulator implementation of an erc20 contract for testing purposes. + * @template P - The private state type, fixed to ERC20PrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class ERC20Simulator + implements IContractSimulator +{ + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockERC20; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor(name: MaybeString, symbol: MaybeString, decimals: bigint) { + this.contract = new MockERC20( + ERC20Witnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)), name, symbol, decimals, + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type ERC20PrivateState. + */ + public getCurrentPrivateState(): ERC20PrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + + /** + * @description Returns the token name. + * @returns The token name. + */ + public name(): MaybeString { + return this.contract.impureCircuits.name(this.circuitContext).result; + } + + /** + * @description Returns the symbol of the token. + * @returns The token name. + */ + public symbol(): MaybeString { + return this.contract.impureCircuits.symbol(this.circuitContext).result; + } + + /** + * @description Returns the number of decimals used to get its user representation. + * @returns The account's token balance. + */ + public decimals(): bigint { + return this.contract.impureCircuits.decimals(this.circuitContext).result; + } + + /** + * @description Returns the value of tokens in existence. + * @returns The total supply of tokens. + */ + public totalSupply(): bigint { + return this.contract.impureCircuits.totalSupply(this.circuitContext).result; + } + + /** + * @description Returns the value of tokens owned by `account`. + * @param account The public key or contract address to query. + * @returns The account's token balance. + */ + public balanceOf(account: Either): bigint { + return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; + } + + /** + * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` + * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. + * @param owner The public key or contract address of approver. + * @param spender The public key or contract address of spender. + * @returns The `spender`'s allowance over `owner`'s tokens. + */ + public allowance( + owner: Either, + spender: Either + ): bigint { + return this.contract.impureCircuits.allowance(this.circuitContext, owner, spender).result; + } + + /** + * @description Moves a `value` amount of tokens from the caller's account to `to`. + * @param to The recipient of the transfer, either a user or a contract. + * @param value The amount to transfer. + * @param sender The simulated caller. + * @returns As per the IERC20 spec, this MUST return true. + */ + public transfer(to: Either, value: bigint, sender?: CoinPublicKey): boolean { + const res = this.contract.impureCircuits.transfer({ + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, to, value + ); + + this.circuitContext = res.context; + return res.result; + } + + /** + * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. + * `value` is the deducted from the caller's allowance. + * @param from The current owner of the tokens for the transfer, either a user or a contract. + * @param to The recipient of the transfer, either a user or a contract. + * @param value The amount to transfer. + * @param sender The simulated caller. + * @returns As per the IERC20 spec, this MUST return true. + */ + public transferFrom( + from: Either, + to: Either, + value: bigint, + sender?: CoinPublicKey + ): boolean { + const res = this.contract.impureCircuits.transferFrom({ + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + from, to, value + ); + + this.circuitContext = res.context; + return res.result; + } + + /** + * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. + * @param spender The Zswap key or ContractAddress that may spend on behalf of the caller. + * @param value The amount of tokens the `spender` may spend. + * @param sender The simulated caller. + * @returns Returns a boolean value indicating whether the operation succeeded. + */ + public approve(spender: Either, value: bigint, sender?: CoinPublicKey): boolean { + const res = this.contract.impureCircuits.approve({ + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + spender, value + ); + + this.circuitContext = res.context; + return res.result; + } + + /// + /// Internal + /// + + /** + * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * @param owner The owner of the tokens. + * @param spender The spender of the tokens. + * @param value The amount of tokens `spender` may spend on behalf of `owner`. + * @returns None. + */ + public _approve( + owner: Either, + spender: Either, + value: bigint + ) { + this.circuitContext = this.contract.impureCircuits._approve(this.circuitContext, owner, spender, value).context; + } + + /** + * @description Moves a `value` amount of tokens from `from` to `to`. + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * @param from The owner of the tokens to transfer. + * @param to The receipient of the transferred tokens. + * @param value The amount of tokens to transfer. + */ + public _transfer( + from: Either, + to: Either, + value: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._transfer(this.circuitContext, from, to, value).context; + } + + /** + * @description Creates a `value` amount of tokens and assigns them to `account`, + * by transferring it from the zero address. Relies on the `update` mechanism. + * @param account The recipient of tokens minted. + * @param value The amount of tokens minted. + */ + public _mint(account: Either, value: bigint) { + this.circuitContext = this.contract.impureCircuits._mint(this.circuitContext, account, value).context; + } + + /** + * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. + * Relies on the `_update` mechanism. + * @param account The target owner of tokens to burn. + * @param value The amount of tokens to burn. + */ + public _burn(account: Either, value: bigint) { + this.circuitContext = this.contract.impureCircuits._burn(this.circuitContext, account, value).context; + } + + /** + * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` + * (or `to`) is the zero address. + * @param from The original owner of the tokens moved (which is 0 if tokens are minted). + * @param to The recipient of the tokens moved (which is 0 if tokens are burned). + * @param value The amount of tokens moved from `from` to `to`. + */ + public _update( + from: Either, + to: Either, + value: bigint + ) { + this.circuitContext = this.contract.impureCircuits._update(this.circuitContext, from, to, value).context; + } + + /** + * @description Updates `owner`'s allowance for `spender` based on spent `value`. + * Does not update the allowance value in case of infinite allowance. + * @param owner The owner of the tokens. + * @param spender The spender of the tokens. + * @param value The amount of token allowance to spend. + */ + public _spendAllowance( + owner: Either, + spender: Either, + value: bigint + ) { + this.circuitContext = this.contract.impureCircuits._spendAllowance(this.circuitContext, owner, spender, value).context; + } + + /** + * @description Returns whether `keyOrAddress` is the zero address. + * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @returns Returns true if `keyOrAddress` is zero. + */ + public isZero(keyOrAddress: Either): boolean { + return this.contract.circuits.isZero(this.circuitContext, keyOrAddress).result; + } +} diff --git a/contracts/erc20/src/test/simulators/index.ts b/contracts/erc20/src/test/simulators/index.ts new file mode 100644 index 00000000..35e6b7c6 --- /dev/null +++ b/contracts/erc20/src/test/simulators/index.ts @@ -0,0 +1 @@ +export { ERC20Simulator } from './ERC20Simulator.js'; \ No newline at end of file diff --git a/contracts/erc20/src/test/types/index.ts b/contracts/erc20/src/test/types/index.ts new file mode 100644 index 00000000..dac4e694 --- /dev/null +++ b/contracts/erc20/src/test/types/index.ts @@ -0,0 +1,6 @@ +export type { IContractSimulator } from './test'; + +export type MaybeString = { + is_some: boolean, + value: string +} diff --git a/contracts/erc20/src/test/types/test.ts b/contracts/erc20/src/test/types/test.ts new file mode 100644 index 00000000..10fb6c98 --- /dev/null +++ b/contracts/erc20/src/test/types/test.ts @@ -0,0 +1,23 @@ +import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; + +/** + * Generic interface for mock contract implementations. + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + */ +export interface IContractSimulator { + /** The contract's deployed address. */ + readonly contractAddress: string; + + /** The current circuit context. */ + circuitContext: CircuitContext

; + + /** Retrieves the current ledger state. */ + getCurrentPublicState(): L; + + /** Retrieves the current private state. */ + getCurrentPrivateState(): P; + + /** Retrieves the current contract state. */ + getCurrentContractState(): ContractState; +} diff --git a/contracts/erc20/src/test/utils/address.ts b/contracts/erc20/src/test/utils/address.ts new file mode 100644 index 00000000..ef9a2842 --- /dev/null +++ b/contracts/erc20/src/test/utils/address.ts @@ -0,0 +1,78 @@ +import { encodeContractAddress } from '@midnight-ntwrk/ledger'; +import * as Compact from '../../artifacts/MockERC20/contract/index.cjs'; +import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; + +const PREFIX_ADDRESS = "0200"; + +export const pad = (s: string, n: number): Uint8Array => { + const encoder = new TextEncoder(); + const utf8Bytes = encoder.encode(s); + if (n < utf8Bytes.length) { + throw new Error(`The padded length n must be at least ${utf8Bytes.length}`); + } + const paddedArray = new Uint8Array(n); + paddedArray.set(utf8Bytes); + return paddedArray; +} + +/** + * @description Generates ZswapCoinPublicKey from `str` for testing purposes. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { + const toHex = Buffer.from(str, 'ascii').toString('hex'); + return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; +} + +/** + * @description Generates ContractAddress from `str` for testing purposes. + * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToAddress = (str: string): Compact.ContractAddress => { + const toHex = Buffer.from(str, 'ascii').toString('hex'); + const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); + return { bytes: encodeContractAddress(fullAddress) }; +} + +/** + * @description Generates an Either object for ZswapCoinPublicKey for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ZswapCoinPublicKey. + */ +export const createEitherTestUser = (str: string) => { + return { + is_left: true, + left: encodeToPK(str), + right: encodeToAddress('') + } +} + +/** + * @description Generates an Either object for ContractAddress for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ContractAddress. + */ +export const createEitherTestContractAddress = (str: string) => { + return { + is_left: false, + left: encodeToPK(''), + right: encodeToAddress(str) + } +} + +export const ZERO_KEY = { + is_left: true, + left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, + right: encodeToAddress('') +} + +export const ZERO_ADDRESS = { + is_left: false, + left: encodeToPK(''), + right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) } +} diff --git a/contracts/erc20/src/test/utils/index.ts b/contracts/erc20/src/test/utils/index.ts new file mode 100644 index 00000000..731fe1ec --- /dev/null +++ b/contracts/erc20/src/test/utils/index.ts @@ -0,0 +1,2 @@ +export { useCircuitContext as circuitContext } from './test'; +export * from './address'; diff --git a/contracts/erc20/src/test/utils/test.ts b/contracts/erc20/src/test/utils/test.ts new file mode 100644 index 00000000..99572ae9 --- /dev/null +++ b/contracts/erc20/src/test/utils/test.ts @@ -0,0 +1,67 @@ +import { + type CircuitContext, + type CoinPublicKey, + type ContractAddress, + type ContractState, + QueryContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import type { IContractSimulator } from '../types'; + +/** + * Constructs a `CircuitContext` from the given state and sender information. + * + * This is typically used at runtime to provide the necessary context + * for executing circuits, including contract state, private state, + * sender identity, and transaction data. + * + * @template P - The type of the contract's private state. + * @param privateState - The current private state of the contract. + * @param contractState - The full contract state, including public and private data. + * @param sender - The public key of the sender (used in the circuit). + * @param contractAddress - The address of the deployed contract. + * @returns A fully populated `CircuitContext` for circuit execution. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContext

( + privateState: P, + contractState: ContractState, + sender: CoinPublicKey, + contractAddress: ContractAddress, +): CircuitContext

{ + return { + originalState: contractState, + currentPrivateState: privateState, + transactionContext: new QueryContext(contractState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} + +/** + * Prepares a new `CircuitContext` using the given sender and contract. + * + * Useful for mocking or updating the circuit context with a custom sender. + * + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + * @template C - The specific type of the contract implementing `MockContract`. + * @param contract - The contract instance implementing `MockContract`. + * @param sender - The public key to set as the sender in the new circuit context. + * @returns A new `CircuitContext` with the sender and updated context values. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContextSender>( + contract: C, + sender: CoinPublicKey, +): CircuitContext

{ + const currentPrivateState = contract.getCurrentPrivateState(); + const originalState = contract.getCurrentContractState(); + const contractAddress = contract.contractAddress; + + return { + originalState, + currentPrivateState, + transactionContext: new QueryContext(originalState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} \ No newline at end of file diff --git a/contracts/erc20/src/witnesses/ERC20Witnesses.ts b/contracts/erc20/src/witnesses/ERC20Witnesses.ts new file mode 100644 index 00000000..ed372fb7 --- /dev/null +++ b/contracts/erc20/src/witnesses/ERC20Witnesses.ts @@ -0,0 +1,3 @@ +// This is how we type an empty object. +export type ERC20PrivateState = Record; +export const ERC20Witnesses = {}; diff --git a/contracts/erc20/src/witnesses/index.ts b/contracts/erc20/src/witnesses/index.ts new file mode 100644 index 00000000..dc29bf8e --- /dev/null +++ b/contracts/erc20/src/witnesses/index.ts @@ -0,0 +1,2 @@ +export * from '../artifacts/erc20/contract/index.cjs'; +export * from './ERC20Witnesses.js'; diff --git a/contracts/erc20/tsconfig.build.json b/contracts/erc20/tsconfig.build.json new file mode 100644 index 00000000..f1132509 --- /dev/null +++ b/contracts/erc20/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["src/test/**/*.ts"], + "compilerOptions": {} +} diff --git a/contracts/erc20/tsconfig.json b/contracts/erc20/tsconfig.json new file mode 100644 index 00000000..3e90b0a9 --- /dev/null +++ b/contracts/erc20/tsconfig.json @@ -0,0 +1,21 @@ +{ + "include": ["src/**/*.ts"], + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "lib": ["ESNext"], + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "node", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": true, + "strict": true, + "isolatedModules": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true + } +} diff --git a/package.json b/package.json index 7c694a14..24105ba7 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,9 @@ "packageManager": "yarn@4.1.0", "workspaces": [ "compact", - "contracts/initializable/*", - "contracts/erc20/*", - "contracts/erc721/*", - "contracts/utils/*" + "contracts/erc20/", + "contracts/initializable/", + "contracts/utils/" ], "scripts": { "compact": "turbo run compact", From c9644c4b88f0b1b8696c5c292508547c834563a1 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 7 Apr 2025 03:09:31 -0500 Subject: [PATCH 036/282] use utils zero address check in erc20 --- contracts/erc20/package.json | 3 ++ contracts/erc20/src/ERC20.compact | 35 ++++++++++--------- .../erc20/src/test/mocks/MockERC20.compact | 4 --- .../src/test/simulators/ERC20Simulator.ts | 9 ----- yarn.lock | 3 +- 5 files changed, 23 insertions(+), 31 deletions(-) diff --git a/contracts/erc20/package.json b/contracts/erc20/package.json index 345721eb..d914daf0 100644 --- a/contracts/erc20/package.json +++ b/contracts/erc20/package.json @@ -20,6 +20,9 @@ "lint": "eslint src", "typecheck": "tsc -p tsconfig.json --noEmit" }, + "dependencies": { + "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" + }, "devDependencies": { "@midnight-ntwrk/compact": "workspace:*", "eslint": "^8.52.0", diff --git a/contracts/erc20/src/ERC20.compact b/contracts/erc20/src/ERC20.compact index 861ca5e9..348113d9 100644 --- a/contracts/erc20/src/ERC20.compact +++ b/contracts/erc20/src/ERC20.compact @@ -22,6 +22,7 @@ pragma language_version >= 0.14.0; */ module ERC20 { import CompactStandardLibrary; + import "../../node_modules/@openzeppelin-midnight-contracts/utils-contract/src/Utils" prefix Utils_; /// Public state export ledger _name: Maybe>; @@ -191,8 +192,8 @@ module ERC20 { spender: Either, value: Uint<128> ): [] { - assert !isZero(owner) "ERC20: invalid owner"; - assert !isZero(spender) "ERC20: invalid spender"; + assert !Utils_isKeyOrAddressZero(owner) "ERC20: invalid owner"; + assert !Utils_isKeyOrAddressZero(spender) "ERC20: invalid spender"; if (!_allowances.member(owner)) { // If owner doesn't exist, create and insert a new sub-map directly _allowances.insert(owner, default, Uint<128>>>); @@ -215,8 +216,8 @@ module ERC20 { to: Either, value: Uint<128> ): [] { - assert !isZero(from) "ERC20: invalid sender"; - assert !isZero(to) "ERC20: invalid receiver"; + assert !Utils_isKeyOrAddressZero(from) "ERC20: invalid sender"; + assert !Utils_isKeyOrAddressZero(to) "ERC20: invalid receiver"; _update(from, to, value); } @@ -233,7 +234,7 @@ module ERC20 { account: Either, value: Uint<128> ): [] { - assert !isZero(account) "ERC20: invalid receiver"; + assert !Utils_isKeyOrAddressZero(account) "ERC20: invalid receiver"; // Using the contract variant of 0 // TODO: Look into if this matters const zero_address = right(ContractAddress{ pad(32, "") }); @@ -253,7 +254,7 @@ module ERC20 { account: Either, value: Uint<128> ): [] { - assert !isZero(account) "ERC20: invalid sender"; + assert !Utils_isKeyOrAddressZero(account) "ERC20: invalid sender"; // Using the contract variant of 0 // TODO: Look into if this matters const zero_address = right(ContractAddress{ pad(32, "") }); @@ -275,7 +276,7 @@ module ERC20 { to: Either, value: Uint<128> ): [] { - if (isZero(from)) { + if (Utils_isKeyOrAddressZero(from)) { // Mint const MAX_UINT128 = 340282366920938463463374607431768211455; assert MAX_UINT128 - _totalSupply >= value "ERC20: arithmetic overflow"; @@ -287,7 +288,7 @@ module ERC20 { _balances.insert(from, fromBal - value as Uint<128>); } - if (isZero(to)) { + if (Utils_isKeyOrAddressZero(to)) { // Burn _totalSupply = _totalSupply - value as Uint<128>; } else { @@ -329,13 +330,13 @@ module ERC20 { * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @return {Boolean} - Returns true if `keyOrAddress` is zero. */ - export pure circuit isZero(keyOrAddress: Either): Boolean { - const zero = pad(32, ""); - - if (keyOrAddress.is_left) { - return keyOrAddress == left(ZswapCoinPublicKey{ zero }); - } else { - return keyOrAddress == right(ContractAddress{ zero }); - } - } + //export pure circuit Utils_isKeyOrAddressZero(keyOrAddress: Either): Boolean { + // const zero = pad(32, ""); +// + // if (keyOrAddress.is_left) { + // return keyOrAddress == left(ZswapCoinPublicKey{ zero }); + // } else { + // return keyOrAddress == right(ContractAddress{ zero }); + // } + //} } diff --git a/contracts/erc20/src/test/mocks/MockERC20.compact b/contracts/erc20/src/test/mocks/MockERC20.compact index 13750b72..e5e8a9da 100644 --- a/contracts/erc20/src/test/mocks/MockERC20.compact +++ b/contracts/erc20/src/test/mocks/MockERC20.compact @@ -104,7 +104,3 @@ export circuit _spendAllowance( ): [] { return ERC20__spendAllowance(owner, spender, value); } - -export pure circuit isZero(keyOrAddress: Either): Boolean { - return ERC20_isZero(keyOrAddress); -} \ No newline at end of file diff --git a/contracts/erc20/src/test/simulators/ERC20Simulator.ts b/contracts/erc20/src/test/simulators/ERC20Simulator.ts index d4b0fb6e..a8e324da 100644 --- a/contracts/erc20/src/test/simulators/ERC20Simulator.ts +++ b/contracts/erc20/src/test/simulators/ERC20Simulator.ts @@ -296,13 +296,4 @@ export class ERC20Simulator ) { this.circuitContext = this.contract.impureCircuits._spendAllowance(this.circuitContext, owner, spender, value).context; } - - /** - * @description Returns whether `keyOrAddress` is the zero address. - * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. - * @returns Returns true if `keyOrAddress` is zero. - */ - public isZero(keyOrAddress: Either): boolean { - return this.contract.circuits.isZero(this.circuitContext, keyOrAddress).result; - } } diff --git a/yarn.lock b/yarn.lock index f83eef79..828e66a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1102,6 +1102,7 @@ __metadata: resolution: "@openzeppelin-midnight-contracts/erc721-contract@workspace:contracts/erc721/contract" dependencies: "@midnight-ntwrk/compact": "workspace:*" + "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" eslint: "npm:^8.52.0" jest: "npm:^29.7.0" typescript: "npm:^5.2.2" @@ -1119,7 +1120,7 @@ __metadata: languageName: unknown linkType: soft -"@openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils": +"@openzeppelin-midnight-contracts/utils-contract@workspace:^, @openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils" dependencies: From 873d3a4ff52cb174338b914222d5a1818aba1ea0 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 7 Apr 2025 03:10:50 -0500 Subject: [PATCH 037/282] fix sim export --- contracts/erc20/src/test/simulators/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/erc20/src/test/simulators/index.ts b/contracts/erc20/src/test/simulators/index.ts index 35e6b7c6..134f9c95 100644 --- a/contracts/erc20/src/test/simulators/index.ts +++ b/contracts/erc20/src/test/simulators/index.ts @@ -1 +1 @@ -export { ERC20Simulator } from './ERC20Simulator.js'; \ No newline at end of file +export { ERC20Simulator } from './ERC20Simulator'; From 2ff7e0e7cae6f70de1442631ec050fe22f0bfe2c Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 7 Apr 2025 03:18:11 -0500 Subject: [PATCH 038/282] remove unused type --- contracts/utils/src/test/types/index.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/contracts/utils/src/test/types/index.ts b/contracts/utils/src/test/types/index.ts index dac4e694..db642b5e 100644 --- a/contracts/utils/src/test/types/index.ts +++ b/contracts/utils/src/test/types/index.ts @@ -1,6 +1 @@ export type { IContractSimulator } from './test'; - -export type MaybeString = { - is_some: boolean, - value: string -} From 9905ed5414a7caeccf107cd8e0a4f8527e5e8c02 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 7 Apr 2025 03:19:16 -0500 Subject: [PATCH 039/282] add line --- contracts/erc20/src/test/utils/test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/erc20/src/test/utils/test.ts b/contracts/erc20/src/test/utils/test.ts index 99572ae9..940ed612 100644 --- a/contracts/erc20/src/test/utils/test.ts +++ b/contracts/erc20/src/test/utils/test.ts @@ -64,4 +64,4 @@ export function useCircuitContextSender transactionContext: new QueryContext(originalState.data, contractAddress), currentZswapLocalState: emptyZswapLocalState(sender), }; -} \ No newline at end of file +} From b40d038fbd75c3989628f0ad9c4a6fa588bbf9df Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Mon, 7 Apr 2025 23:31:03 -0400 Subject: [PATCH 040/282] Restructure workspace to match ERC20, adds working tests --- contracts/erc721/.eslintignore | 1 + contracts/erc721/contract/src/erc721.compact | 33 ----- contracts/erc721/contract/src/index.ts | 2 - contracts/erc721/src/ERC721.compact | 100 ++++++++++++++ contracts/erc721/src/test/erc721.test.ts | 78 +++++++++++ .../erc721/src/test/mocks/MockERC721.compact | 32 +++++ .../src/test/simulators/ERC721Simulator.ts | 122 ++++++++++++++++++ contracts/erc721/src/test/simulators/index.ts | 1 + contracts/erc721/src/test/types/test.ts | 23 ++++ contracts/erc721/src/test/utils/index.ts | 2 + contracts/erc721/src/test/utils/test.ts | 67 ++++++++++ .../witnesses/ERC721Witnesses.ts} | 6 +- contracts/erc721/src/witnesses/index.ts | 2 + 13 files changed, 429 insertions(+), 40 deletions(-) create mode 100644 contracts/erc721/.eslintignore delete mode 100644 contracts/erc721/contract/src/erc721.compact delete mode 100644 contracts/erc721/contract/src/index.ts create mode 100644 contracts/erc721/src/ERC721.compact create mode 100644 contracts/erc721/src/test/erc721.test.ts create mode 100644 contracts/erc721/src/test/mocks/MockERC721.compact create mode 100644 contracts/erc721/src/test/simulators/ERC721Simulator.ts create mode 100644 contracts/erc721/src/test/simulators/index.ts create mode 100644 contracts/erc721/src/test/types/test.ts create mode 100644 contracts/erc721/src/test/utils/index.ts create mode 100644 contracts/erc721/src/test/utils/test.ts rename contracts/erc721/{contract/src/witnesses.ts => src/witnesses/ERC721Witnesses.ts} (53%) create mode 100644 contracts/erc721/src/witnesses/index.ts diff --git a/contracts/erc721/.eslintignore b/contracts/erc721/.eslintignore new file mode 100644 index 00000000..327555cd --- /dev/null +++ b/contracts/erc721/.eslintignore @@ -0,0 +1 @@ +src/artifacts diff --git a/contracts/erc721/contract/src/erc721.compact b/contracts/erc721/contract/src/erc721.compact deleted file mode 100644 index f14c79d2..00000000 --- a/contracts/erc721/contract/src/erc721.compact +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.14.0; - -import CompactStandardLibrary; - -export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; - -/// Public state -export sealed ledger name: Maybe>; -export sealed ledger symbol: Maybe>; -export ledger owners: Map, Either>; -export ledger balances: Map, Uint<256>>; -export ledger tokenApprovals: Map, Either>; -export ledger operatorApprovals: Map, Map, >; - -/** - * @description Initializes the contract. - * @dev Move logic to initializer to set this as a base contract. - * - * @param _name - The name of the token. - * @param _symbol - The symbol of the token. - * @param _decimals - The number of decimals used to get the user representation. - */ -constructor( - _name: Maybe>, - _symbol: Maybe>, -) { - name = _name; - symbol = _symbol; -} - - diff --git a/contracts/erc721/contract/src/index.ts b/contracts/erc721/contract/src/index.ts deleted file mode 100644 index b2fe5df9..00000000 --- a/contracts/erc721/contract/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './artifacts/erc721/contract/index.cjs'; -export * from './witnesses.js'; diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact new file mode 100644 index 00000000..60cec861 --- /dev/null +++ b/contracts/erc721/src/ERC721.compact @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.14.0; + +/** + * @module ERC721 + * @description An unshielded ERC721 library. + * + * @notice ADD + * + * @notice Further discussion and consideration required: + * + * - Consider changing the underscore in the internal methods to `unsafe` or + * adopting dot notation for prefixing imports. + * - Revise logic once contract-to-contract interactions are available on midnight. + * - Consider implementing an introspection mechanism for transfers to contracts. + * - Standardize which zero address to use (`ZswapCoinPublicKey` or `ContractAddress`). + */ +module ERC721 { + import CompactStandardLibrary; + import "../../node_modules/@openzeppelin-midnight-contracts/utils-contract/src/Utils" prefix Utils_; + + /// Public state + export sealed ledger _name: Maybe>; + export sealed ledger _symbol: Maybe>; + export ledger _owners: Map>; + export ledger _balances: Map, Uint<128>>; + export ledger _tokenApprovals: Map>; + export ledger _operatorApprovals: Map, Map, Boolean>>; + + /** + * @description Initializes the contract by setting the name and symbol. + * + * @param name_ - The name of the token. + * @param symbol_ - The symbol of the token. + */ + export circuit initializer( + name_: Maybe>, + symbol_: Maybe> + ): [] { + _name = name_; + _symbol = symbol_; + } + + /** + * @description Returns the token name. + * + * @return {Maybe>} - The token name. + */ + export circuit name(): Maybe> { + return _name; + } + + /** + * @description Returns the symbol of the token. + * + * @return {Maybe>} - The token name. + */ + export circuit symbol(): Maybe> { + return _symbol; + } + + + /** + * @description Returns the value of tokens owned by `account`. + * + * @dev Manually checks if `account` is a key in the map and returns 0 if it is not. + * + * @param {account} - The public key or contract address to query. + * @return {Uint<128>} - The account's token balance. + */ + export circuit balanceOf(account: Either): Uint<128> { + if (!_balances.member(account)) { + return 0; + } + + return _balances.lookup(account); + } + + export circuit ownerOf(tokenId: Field): Either { + return _requireOwned(tokenId); + } + + circuit _requireOwned(tokenId: Field): Either { + const owner = _ownerOf(tokenId); + assert !Utils_isKeyOrAddressZero(owner) "ERC721: Invalid Owner"; + return owner; + } + + circuit _ownerOf(tokenId: Field): Either { + if (!_owners.member(tokenId)) { + // If tokenId doesn't exist, create and insert a default value + // What is default value?? + _owners.insert(tokenId, default>); + } + return _owners.lookup(tokenId); + } + +} + diff --git a/contracts/erc721/src/test/erc721.test.ts b/contracts/erc721/src/test/erc721.test.ts new file mode 100644 index 00000000..518bd866 --- /dev/null +++ b/contracts/erc721/src/test/erc721.test.ts @@ -0,0 +1,78 @@ +import { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; +import { ERC721Simulator } from './simulators'; +import { MaybeString } from './types'; +import * as utils from './utils'; + +const NO_STRING: MaybeString = { + is_some: false, + value: '' +}; +const NAME: MaybeString = { + is_some: true, + value: "NAME" +}; +const SYMBOL: MaybeString = { + is_some: true, + value: "SYMBOL" +}; + +const TOKENID: bigint = BigInt(1); + +const AMOUNT: bigint = BigInt(250); +const MAX_UINT128 = BigInt(2 ** 128) - BigInt(1); + +const OWNER = String(Buffer.from("OWNER", 'ascii').toString('hex')).padStart(64, '0'); +const SPENDER = String(Buffer.from("SPENDER", 'ascii').toString('hex')).padStart(64, '0'); +const UNAUTHORIZED = String(Buffer.from("UNAUTHORIZED", 'ascii').toString('hex')).padStart(64, '0'); +const ZERO = String().padStart(64, '0'); +const Z_OWNER = utils.createEitherTestUser('OWNER'); +const Z_RECIPIENT = utils.createEitherTestUser('RECIPIENT'); +const Z_SPENDER = utils.createEitherTestUser('SPENDER'); +const Z_OTHER = utils.createEitherTestUser('OTHER'); +const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); + +let token: ERC721Simulator; +let caller: CoinPublicKey; + +describe('ERC721', () => { + describe('initializer and metadata', () => { + it('should initialize metadata', () => { + token = new ERC721Simulator(NAME, SYMBOL); + + expect(token.name()).toEqual(NAME); + expect(token.symbol()).toEqual(SYMBOL); + }); + + it('should initialize empty metadata', () => { + token = new ERC721Simulator(NO_STRING, NO_STRING); + + expect(token.name()).toEqual(NO_STRING); + expect(token.symbol()).toEqual(NO_STRING); + }); + }); + + beforeEach(() => { + token = new ERC721Simulator(NAME, SYMBOL); + }); + + describe('balanceOf', () => { + it('should return zero when requested account has no balance', () => { + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + + /* it('should return balance when requested account has tokens', () => { + token._mint(Z_OWNER, AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + }); */ + }); + + describe('ownerOf', () => { + it('should throw if tokenId does not exist', () => { + expect(() => { + token.ownerOf(TOKENID); + }).toThrow('ERC721: Invalid Owner'); + }) + }) + + +}); diff --git a/contracts/erc721/src/test/mocks/MockERC721.compact b/contracts/erc721/src/test/mocks/MockERC721.compact new file mode 100644 index 00000000..8060593f --- /dev/null +++ b/contracts/erc721/src/test/mocks/MockERC721.compact @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.14.0; + +import CompactStandardLibrary; + +import "../../ERC721" prefix ERC721_; + +export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; + +constructor( + _name: Maybe>, + _symbol: Maybe> +) { + ERC721_initializer(_name, _symbol); +} + +export circuit name(): Maybe> { + return ERC721_name(); +} + +export circuit symbol(): Maybe> { + return ERC721_symbol(); +} + +export circuit balanceOf(account: Either): Uint<128> { + return ERC721_balanceOf(account); +} + +export circuit ownerOf(tokenId: Field): Either { + return ERC721_ownerOf(tokenId); +} \ No newline at end of file diff --git a/contracts/erc721/src/test/simulators/ERC721Simulator.ts b/contracts/erc721/src/test/simulators/ERC721Simulator.ts new file mode 100644 index 00000000..6e7fc37e --- /dev/null +++ b/contracts/erc721/src/test/simulators/ERC721Simulator.ts @@ -0,0 +1,122 @@ +import { + type CircuitContext, + CoinPublicKey, + type ContractState, + QueryContext, + constructorContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import { sampleContractAddress } from '@midnight-ntwrk/zswap'; +import { + type Ledger, + Contract as MockERC721, + ledger, + Either, + ZswapCoinPublicKey, + ContractAddress, +} from '../../artifacts/MockERC721/contract/index.cjs'; // Combined imports +import { MaybeString } from '../types'; +import type { IContractSimulator } from '../types'; +import { ERC721PrivateState, ERC721Witnesses } from '../../witnesses'; + +/** + * @description A simulator implementation of an ERC721 contract for testing purposes. + * @template P - The private state type, fixed to ERC721PrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class ERC721Simulator + implements IContractSimulator { + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockERC721; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor(name: MaybeString, symbol: MaybeString) { + this.contract = new MockERC721( + ERC721Witnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)), name, symbol, + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type ERC721PrivateState. + */ + public getCurrentPrivateState(): ERC721PrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + + /** + * @description Returns the token name. + * @returns The token name. + */ + public name(): MaybeString { + return this.contract.impureCircuits.name(this.circuitContext).result; + } + + /** + * @description Returns the symbol of the token. + * @returns The token name. + */ + public symbol(): MaybeString { + return this.contract.impureCircuits.symbol(this.circuitContext).result; + } + + /** + * @description Returns the value of tokens owned by `account`. + * @param account The public key or contract address to query. + * @returns The account's token balance. + */ + public balanceOf(account: Either): bigint { + return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; + } + + /** + * @description Returns the owner of `tokenId`. + * @param tokenId The Id of the token to query. + * @returns The account owner of the token. + */ + public ownerOf(tokenId: bigint): Either { + return this.contract.impureCircuits.ownerOf(this.circuitContext, tokenId).result; + } +} + diff --git a/contracts/erc721/src/test/simulators/index.ts b/contracts/erc721/src/test/simulators/index.ts new file mode 100644 index 00000000..21479682 --- /dev/null +++ b/contracts/erc721/src/test/simulators/index.ts @@ -0,0 +1 @@ +export { ERC721Simulator } from './ERC721Simulator'; diff --git a/contracts/erc721/src/test/types/test.ts b/contracts/erc721/src/test/types/test.ts new file mode 100644 index 00000000..10fb6c98 --- /dev/null +++ b/contracts/erc721/src/test/types/test.ts @@ -0,0 +1,23 @@ +import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; + +/** + * Generic interface for mock contract implementations. + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + */ +export interface IContractSimulator { + /** The contract's deployed address. */ + readonly contractAddress: string; + + /** The current circuit context. */ + circuitContext: CircuitContext

; + + /** Retrieves the current ledger state. */ + getCurrentPublicState(): L; + + /** Retrieves the current private state. */ + getCurrentPrivateState(): P; + + /** Retrieves the current contract state. */ + getCurrentContractState(): ContractState; +} diff --git a/contracts/erc721/src/test/utils/index.ts b/contracts/erc721/src/test/utils/index.ts new file mode 100644 index 00000000..731fe1ec --- /dev/null +++ b/contracts/erc721/src/test/utils/index.ts @@ -0,0 +1,2 @@ +export { useCircuitContext as circuitContext } from './test'; +export * from './address'; diff --git a/contracts/erc721/src/test/utils/test.ts b/contracts/erc721/src/test/utils/test.ts new file mode 100644 index 00000000..940ed612 --- /dev/null +++ b/contracts/erc721/src/test/utils/test.ts @@ -0,0 +1,67 @@ +import { + type CircuitContext, + type CoinPublicKey, + type ContractAddress, + type ContractState, + QueryContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import type { IContractSimulator } from '../types'; + +/** + * Constructs a `CircuitContext` from the given state and sender information. + * + * This is typically used at runtime to provide the necessary context + * for executing circuits, including contract state, private state, + * sender identity, and transaction data. + * + * @template P - The type of the contract's private state. + * @param privateState - The current private state of the contract. + * @param contractState - The full contract state, including public and private data. + * @param sender - The public key of the sender (used in the circuit). + * @param contractAddress - The address of the deployed contract. + * @returns A fully populated `CircuitContext` for circuit execution. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContext

( + privateState: P, + contractState: ContractState, + sender: CoinPublicKey, + contractAddress: ContractAddress, +): CircuitContext

{ + return { + originalState: contractState, + currentPrivateState: privateState, + transactionContext: new QueryContext(contractState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} + +/** + * Prepares a new `CircuitContext` using the given sender and contract. + * + * Useful for mocking or updating the circuit context with a custom sender. + * + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + * @template C - The specific type of the contract implementing `MockContract`. + * @param contract - The contract instance implementing `MockContract`. + * @param sender - The public key to set as the sender in the new circuit context. + * @returns A new `CircuitContext` with the sender and updated context values. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContextSender>( + contract: C, + sender: CoinPublicKey, +): CircuitContext

{ + const currentPrivateState = contract.getCurrentPrivateState(); + const originalState = contract.getCurrentContractState(); + const contractAddress = contract.contractAddress; + + return { + originalState, + currentPrivateState, + transactionContext: new QueryContext(originalState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} diff --git a/contracts/erc721/contract/src/witnesses.ts b/contracts/erc721/src/witnesses/ERC721Witnesses.ts similarity index 53% rename from contracts/erc721/contract/src/witnesses.ts rename to contracts/erc721/src/witnesses/ERC721Witnesses.ts index b66d496b..983ff01e 100644 --- a/contracts/erc721/contract/src/witnesses.ts +++ b/contracts/erc721/src/witnesses/ERC721Witnesses.ts @@ -1,7 +1,3 @@ // This is how we type an empty object. export type ERC721PrivateState = Record; - -export const witnesses = {}; - -export const createERC721PrivateState = () => ({ -}); +export const ERC721Witnesses = {}; diff --git a/contracts/erc721/src/witnesses/index.ts b/contracts/erc721/src/witnesses/index.ts new file mode 100644 index 00000000..5b4961a0 --- /dev/null +++ b/contracts/erc721/src/witnesses/index.ts @@ -0,0 +1,2 @@ +export * from '../artifacts/erc721/contract/index.cjs'; +export * from './ERC721Witnesses.js'; From 09b50b5d796e6b8e5cc3e09b869edbe9e7c3701a Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Tue, 8 Apr 2025 18:56:48 -0400 Subject: [PATCH 041/282] WIP impl transferFrom and its dependent private functions --- contracts/erc721/src/ERC721.compact | 102 ++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 60cec861..ad36536c 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -96,5 +96,107 @@ module ERC721 { return _owners.lookup(tokenId); } + export circuit transferFrom( + from: Either, + to: Either, + tokenId: Field + ): [] { + assert !Utils_isKeyOrAddressZero(to) "ERC721: Invalid Receiver"; + // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists + // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. + + // Assumes sender is a ZSwapPublicKey + // Need to revisit once we have contract <> contract communication + const previousOwner = _update(to, tokenId, own_public_key()); + assert previousOwner != from "ERC721: Incorrect Owner"; + } + + circuit _update( + to: Either, + tokenId: Field, + auth: Either + ): Either { + from = _ownerOf(tokenId); + + // Perform (optional) operator check + if (!Utils_isKeyOrAddressZero(auth)) { + _checkAuthorized(from, auth, tokenId); + } + + // execute update + if (!Utils_isKeyOrAddressZero(from)) { + // assuming burn address == zero address + // Need to test to confirm + _approve(burn_address(), tokenId, burn_address(), false); + const newBalance = _balances.lookup(from) - 1 as Uint<128>; + _balances.insert(tokenId, newBalance); + } + + if (!Utils_isKeyOrAddressZero(to)) { + const newBalance = _balances.lookup(to) + 1 as Uint<128>; + _balances.insert(tokenId, newBalance); + } + + _owners.insert(tokenId, to); + + return from; + } + + circuit _approve( + to: Either, + tokenId: Field, + auth: Either, + emitEvent: Boolean + ): [] { + if (emitEvent || !Utils_isKeyOrAddressZero(auth)) { + owner = _requireOwned(tokenId); + + // We do not use _isAuthorized because single-token approvals should not be able to call approve + assert (!Utils_isKeyOrAddressZero(auth) && owner != auth && !isApprovedForAll(owner, auth)) "ERC721 Invalid Approver" + + // if (emitEvent) { + // impl event here when available + // } + } + + _tokenApprovals.insert(tokenId, to); + } + + circuit _checkAuthorized( + owner: Either, + spender: Either, + tokenId: Field + ): [] { + if (!_isAuthorized(owner, spender, tokenId)) { + assert !Utils_isKeyOrAddressZero(owner) "ERC721: Nonexistent Token" + assert false "ERC721: Insufficient Approval" + } + } + + circuit _isAuthorized( + owner: Either, + spender: Either, + tokenId: Field + ): Boolean { + return !Utils_isKeyOrAddressZero(spender) && (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender) + } + + export circuit isApprovedForAll( + owner: Either, + operator: Either + ): Boolean { + if (_operatorApprovals.member(owner) && _operatorApprovals.lookup(owner).member(spender)) { + return _operatorApprovals.lookup(owner).lookup(spender); + } else { + return false; + } + } + + circuit _getApproved(tokenId: Field): Either { + // I think this returns the 0 address if token doesn't exist + // Make sure this doesn't cause problem in testing + return _tokenApprovals.lookup(tokenId); + } + } From e6f63f127e7162089d83f24dd104b02c9b677426 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 8 Apr 2025 14:48:38 -0500 Subject: [PATCH 042/282] erc20 unshielded (#1) * test: adding more tests in ERC20 contract * catch mint overflow to output a more readable error msg * add overflow tests * fix test assertions * add initial module doc * remove contract dir * re-add erc20 * use utils zero address check in erc20 * fix sim export * remove file * remove unused type * add line * set metadata as sealed * add initializer comment * add return comment to initializer --------- Co-authored-by: 0xisk --- contracts/erc20/src/ERC20.compact | 342 ------------------ contracts/erc20/src/test/erc20.test.ts | 471 +++++++++++++++++++++++++ contracts/utils/.eslintignore | 1 + contracts/utils/.eslintrc.cjs | 30 ++ contracts/utils/js-resolver.cjs | 16 + contracts/utils/package.json | 32 ++ contracts/utils/tsconfig.build.json | 5 + contracts/utils/tsconfig.json | 21 ++ yarn.lock | 1 + 9 files changed, 577 insertions(+), 342 deletions(-) delete mode 100644 contracts/erc20/src/ERC20.compact create mode 100644 contracts/erc20/src/test/erc20.test.ts create mode 100644 contracts/utils/.eslintignore create mode 100644 contracts/utils/.eslintrc.cjs create mode 100644 contracts/utils/js-resolver.cjs create mode 100644 contracts/utils/package.json create mode 100644 contracts/utils/tsconfig.build.json create mode 100644 contracts/utils/tsconfig.json diff --git a/contracts/erc20/src/ERC20.compact b/contracts/erc20/src/ERC20.compact deleted file mode 100644 index 348113d9..00000000 --- a/contracts/erc20/src/ERC20.compact +++ /dev/null @@ -1,342 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.14.0; - -/** - * @module ERC20 - * @description An unshielded ERC20 library. - * - * @notice One notable difference regarding this implementation and the EIP20 spec - * consists of the token size. Uint<128> is used as the token size because Uint<256> - * cannot be supported. - * This is due to encoding limits on the midnight circuit backend: - * https://github.com/midnightntwrk/compactc/issues/929 - * - * @notice Further discussion and consideration required: - * - * - Consider changing the underscore in the internal methods to `unsafe` or - * adopting dot notation for prefixing imports. - * - Revise logic once contract-to-contract interactions are available on midnight. - * - Consider implementing an introspection mechanism for transfers to contracts. - * - Standardize which zero address to use (`ZswapCoinPublicKey` or `ContractAddress`). - */ -module ERC20 { - import CompactStandardLibrary; - import "../../node_modules/@openzeppelin-midnight-contracts/utils-contract/src/Utils" prefix Utils_; - - /// Public state - export ledger _name: Maybe>; - export ledger _symbol: Maybe>; - export ledger _decimals: Uint<8>; - export ledger _totalSupply: Uint<128>; - export ledger _balances: Map, Uint<128>>; - export ledger _allowances: Map, Map, Uint<128>>>; - - /** - * @description Initializes the contract by setting the name, symbol, and decimals. - * - * @param name_ - The name of the token. - * @param symbol_ - The symbol of the token. - * @param decimals_ - The number of decimals used to get the user representation. - */ - export circuit initializer( - name_: Maybe>, - symbol_: Maybe>, - decimals_:Uint<8> - ): [] { - _name = name_; - _symbol = symbol_; - _decimals = decimals_; - } - - /** - * @description Returns the token name. - * - * @return {Maybe>} - The token name. - */ - export circuit name(): Maybe> { - return _name; - } - - /** - * @description Returns the symbol of the token. - * - * @return {Maybe>} - The token name. - */ - export circuit symbol(): Maybe> { - return _symbol; - } - - /** - * @description Returns the number of decimals used to get its user representation. - * - * @return {Uint<8>} - The account's token balance. - */ - export circuit decimals(): Uint<8> { - return _decimals; - } - - /** - * @description Returns the value of tokens in existence. - * - * @return {Uint<128>} - The total supply of tokens. - */ - export circuit totalSupply(): Uint<128> { - return _totalSupply; - } - - /** - * @description Returns the value of tokens owned by `account`. - * - * @dev Manually checks if `account` is a key in the map and returns 0 if it is not. - * - * @param {account} - The public key or contract address to query. - * @return {Uint<128>} - The account's token balance. - */ - export circuit balanceOf(account: Either): Uint<128> { - if (!_balances.member(account)) { - return 0; - } - - return _balances.lookup(account); - } - - /** - * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` - * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. - * - * @dev Manually checks if `owner` and `spender` are keys in the map and returns 0 if they are not. - * - * @param {owner} - The public key or contract address of approver. - * @param {spender} - The public key or contract address of spender. - * @return {Uint<128>} - The `spender`'s allowance over `owner`'s tokens. - */ - export circuit allowance( - owner: Either, - spender: Either - ): Uint<128> { - if (!_allowances.member(owner) || !_allowances.lookup(owner).member(spender)) { - return 0; - } - - return _allowances.lookup(owner).lookup(spender); - } - - /** - * @description Moves a `value` amount of tokens from the caller's account to `to`. - * - * @dev We need to get the caller address from contracts and handle the transfer appropriately. - * This should include a callback to ensure the contract can safely receive tokens. - * - * @param {to} - The recipient of the transfer, either a user or a contract. - * @param {value} - The amount to transfer. - * @return {Boolean} - As per the IERC20 spec, this MUST return true. - */ - export circuit transfer(to: Either, value: Uint<128>): Boolean { - // TMP - Waiting for contract-to-contract calls to handle `right` with contract address - const owner = left(own_public_key()); - _transfer(owner, to, value); - return true; - } - - /** - * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. - * `value` is the deducted from the caller's allowance. - * - * @dev We need to get the caller address from contracts and handle the transfer appropriately. - * This should include a callback to ensure the contract can safely receive tokens. - * - * @param {from} - The current owner of the tokens for the transfer, either a user or a contract. - * @param {to} - The recipient of the transfer, either a user or a contract. - * @param {value} - The amount to transfer. - * @return {Boolean} - As per the IERC20 spec, this MUST return true. - */ - export circuit transferFrom( - from: Either, - to: Either, - value: Uint<128> - ): Boolean { - // TMP - Waiting for contract-to-contract calls to handle `right` with contract address - const spender = left(own_public_key()); - _spendAllowance(from, spender, value); - _transfer(from, to, value); - return true; - } - - /** - * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. - * - * @param {spender} - The Zswap key or ContractAddress that may spend on behalf of the caller. - * @param {value} - The amount of tokens the `spender` may spend. - * @return {Boolean} - Returns a boolean value indicating whether the operation succeeded. - */ - export circuit approve(spender: Either, value: Uint<128>): Boolean { - // TMP - Waiting for contract-to-contract calls to handle `right` with contract address - const owner = left(own_public_key()); - _approve(owner, spender, value); - return true; - } - - /** - * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. - * This internal function is equivalent to `approve`, and can be used to - * e.g. set automatic allowances for certain subsystems, etc. - * - * @param {owner} - The owner of the tokens. - * @param {spender} - The spender of the tokens. - * @param {value} - The amount of tokens `spender` may spend on behalf of `owner`. - * @return {[]} - None. - */ - export circuit _approve( - owner: Either, - spender: Either, - value: Uint<128> - ): [] { - assert !Utils_isKeyOrAddressZero(owner) "ERC20: invalid owner"; - assert !Utils_isKeyOrAddressZero(spender) "ERC20: invalid spender"; - if (!_allowances.member(owner)) { - // If owner doesn't exist, create and insert a new sub-map directly - _allowances.insert(owner, default, Uint<128>>>); - } - _allowances.lookup(owner).insert(spender, value); - } - - /** - * @description Moves a `value` amount of tokens from `from` to `to`. - * This internal function is equivalent to {transfer}, and can be used to - * e.g. implement automatic token fees, slashing mechanisms, etc. - * - * @param {from} - The owner of the tokens to transfer. - * @param {to} - The receipient of the transferred tokens. - * @param {value} - The amount of tokens to transfer. - * @return {[]} - None. - */ - export circuit _transfer( - from: Either, - to: Either, - value: Uint<128> - ): [] { - assert !Utils_isKeyOrAddressZero(from) "ERC20: invalid sender"; - assert !Utils_isKeyOrAddressZero(to) "ERC20: invalid receiver"; - - _update(from, to, value); - } - - /** - * @description Creates a `value` amount of tokens and assigns them to `account`, - * by transferring it from the zero address. Relies on the `update` mechanism. - * - * @param {account} - The recipient of tokens minted. - * @param {value} - The amount of tokens minted. - * @return {[]} - None. - */ - export circuit _mint( - account: Either, - value: Uint<128> - ): [] { - assert !Utils_isKeyOrAddressZero(account) "ERC20: invalid receiver"; - // Using the contract variant of 0 - // TODO: Look into if this matters - const zero_address = right(ContractAddress{ pad(32, "") }); - - _update(zero_address, account, value); - } - - /** - * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. - * Relies on the `_update` mechanism. - * - * @param {account} - The target owner of tokens to burn. - * @param {value} - The amount of tokens to burn. - * @return {[]} - None. - */ - export circuit _burn( - account: Either, - value: Uint<128> - ): [] { - assert !Utils_isKeyOrAddressZero(account) "ERC20: invalid sender"; - // Using the contract variant of 0 - // TODO: Look into if this matters - const zero_address = right(ContractAddress{ pad(32, "") }); - _update(account, zero_address, value); - } - - /** - * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` - * (or `to`) is the zero address. - * @dev Checks for a mint overflow in order to output a more readable error message. - * - * @param {from} - The original owner of the tokens moved (which is 0 if tokens are minted). - * @param {to} - The recipient of the tokens moved (which is 0 if tokens are burned). - * @param {value} - The amount of tokens moved from `from` to `to`. - * @return {[]} - None. - */ - export circuit _update( - from: Either, - to: Either, - value: Uint<128> - ): [] { - if (Utils_isKeyOrAddressZero(from)) { - // Mint - const MAX_UINT128 = 340282366920938463463374607431768211455; - assert MAX_UINT128 - _totalSupply >= value "ERC20: arithmetic overflow"; - - _totalSupply = _totalSupply + value as Uint<128>; - } else { - const fromBal = balanceOf(from); - assert fromBal >= value "ERC20: insufficient balance"; - _balances.insert(from, fromBal - value as Uint<128>); - } - - if (Utils_isKeyOrAddressZero(to)) { - // Burn - _totalSupply = _totalSupply - value as Uint<128>; - } else { - const toBal = balanceOf(to); - _balances.insert(to, toBal + value as Uint<128>); - } - } - - /** - * @description Updates `owner`'s allowance for `spender` based on spent `value`. - * Does not update the allowance value in case of infinite allowance. - * - * @param {owner} - The owner of the tokens. - * @param {spender} - The spender of the tokens. - * @param {value} - The amount of token allowance to spend. - * @return {[]} - None. - */ - export circuit _spendAllowance( - owner: Either, - spender: Either, - value: Uint<128> - ): [] { - // TODO: Look into improving design so we're not checking allowance member twice (here and in `_approve`) - assert (_allowances.member(owner) && _allowances.lookup(owner).member(spender)) "ERC20: insufficient allowance"; - - const currentAllowance = _allowances.lookup(owner).lookup(spender); - // TODO: improve readability of max_u128 - const MAX_UINT128 = 340282366920938463463374607431768211455; - if (currentAllowance < MAX_UINT128) { - assert currentAllowance >= value "ERC20: insufficient allowance"; - _approve(owner, spender, currentAllowance - value as Uint<128>); - } - } - - /** - * @description Returns whether `keyOrAddress` is the zero address. - * @todo Move to a utils contract since this will likely be reused. - * - * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. - * @return {Boolean} - Returns true if `keyOrAddress` is zero. - */ - //export pure circuit Utils_isKeyOrAddressZero(keyOrAddress: Either): Boolean { - // const zero = pad(32, ""); -// - // if (keyOrAddress.is_left) { - // return keyOrAddress == left(ZswapCoinPublicKey{ zero }); - // } else { - // return keyOrAddress == right(ContractAddress{ zero }); - // } - //} -} diff --git a/contracts/erc20/src/test/erc20.test.ts b/contracts/erc20/src/test/erc20.test.ts new file mode 100644 index 00000000..939f1c2b --- /dev/null +++ b/contracts/erc20/src/test/erc20.test.ts @@ -0,0 +1,471 @@ +import { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; +import { ERC20Simulator } from './simulators'; +import { MaybeString } from './types'; +import * as utils from './utils'; + +const NO_STRING: MaybeString = { + is_some: false, + value: '' +}; +const NAME: MaybeString = { + is_some: true, + value: "NAME" +}; +const SYMBOL: MaybeString = { + is_some: true, + value: "SYMBOL" +}; +const DECIMALS: bigint = 18n; + +const AMOUNT: bigint = BigInt(250); +const MAX_UINT128 = BigInt(2**128) - BigInt(1); + +const OWNER = String(Buffer.from("OWNER", 'ascii').toString('hex')).padStart(64, '0'); +const SPENDER = String(Buffer.from("SPENDER", 'ascii').toString('hex')).padStart(64, '0'); +const UNAUTHORIZED = String(Buffer.from("UNAUTHORIZED", 'ascii').toString('hex')).padStart(64, '0'); +const ZERO = String().padStart(64, '0'); +const Z_OWNER = utils.createEitherTestUser('OWNER'); +const Z_RECIPIENT = utils.createEitherTestUser('RECIPIENT'); +const Z_SPENDER = utils.createEitherTestUser('SPENDER'); +const Z_OTHER = utils.createEitherTestUser('OTHER'); +const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); + +let token: ERC20Simulator; +let caller: CoinPublicKey; + +describe('ERC20', () => { + describe('initializer and metadata', () => { + it('should initialize metadata', () => { + token = new ERC20Simulator(NAME, SYMBOL, DECIMALS); + + expect(token.name()).toEqual(NAME); + expect(token.symbol()).toEqual(SYMBOL); + expect(token.decimals()).toEqual(DECIMALS); + }); + + it('should initialize empty metadata', () => { + const NO_DECIMALS = 0n; + token = new ERC20Simulator(NO_STRING, NO_STRING, NO_DECIMALS); + + expect(token.name()).toEqual(NO_STRING); + expect(token.symbol()).toEqual(NO_STRING); + expect(token.decimals()).toEqual(NO_DECIMALS); + }); + }); + + beforeEach(() => { + token = new ERC20Simulator(NAME, SYMBOL, DECIMALS); + }); + + describe('totalSupply', () => { + it('returns 0 when there is no supply', () => { + expect(token.totalSupply()).toEqual(0n); + }); + + it('returns the amount of existing tokens when there is a supply', () => { + token._mint(Z_OWNER, AMOUNT); + expect(token.totalSupply()).toEqual(AMOUNT); + }) + }) + + describe('balanceOf', () => { + it('should return zero when requested account has no balance', () => { + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + + it('should return balance when requested account has tokens', () => { + token._mint(Z_OWNER, AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + }); + }); + + describe('transfer', () => { + beforeEach(() => { + token._mint(Z_OWNER, AMOUNT); + + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); + }); + + afterEach(() => { + expect(token.totalSupply()).toEqual(AMOUNT); + }); + + it('should transfer partial', () => { + const partialAmt = AMOUNT - 1n; + caller = OWNER; + const txSuccess = token.transfer(Z_RECIPIENT, partialAmt, caller); + + expect(txSuccess).toBeTruthy(); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); + }); + + it('should transfer full', () => { + caller = OWNER; + const txSuccess = token.transfer(Z_RECIPIENT, AMOUNT, caller); + + expect(txSuccess).toBeTruthy(); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); + }); + + it('should fail with insufficient balance', () => { + caller = OWNER; + + expect(() => { + token.transfer(Z_RECIPIENT, AMOUNT + 1n, caller); + }).toThrow('ERC20: insufficient balance'); + }); + + it('should fail with transfer from zero', () => { + caller = ZERO; + + expect(() => { + token.transfer(Z_RECIPIENT, AMOUNT, caller); + }).toThrow('ERC20: invalid sender'); + }); + + it('should fail with transfer to zero', () => { + caller = OWNER; + + expect(() => { + token.transfer(utils.ZERO_ADDRESS, AMOUNT, caller); + }).toThrow('ERC20: invalid receiver'); + }); + + it('should allow transfer of 0 tokens', () => { + const txSuccess = token.transfer(Z_RECIPIENT, 0n, caller); + + expect(txSuccess).toBeTruthy(); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); + }); + + it('should handle transfer with empty _balances', () => { + caller = SPENDER; + + expect(() => { + token.transfer(Z_RECIPIENT, 1n, caller); + }).toThrow('ERC20: insufficient balance'); + }); + }); + + describe('approve', () => { + beforeEach(() => { + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + + it('should approve and update allowance', () => { + caller = OWNER; + + token.approve(Z_SPENDER, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); + }); + + it('should approve and update allowance for multiple spenders', () => { + caller = OWNER; + + token.approve(Z_SPENDER, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); + + token.approve(Z_OTHER, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_OTHER)).toEqual(AMOUNT); + + expect(token.allowance(Z_OWNER, Z_RECIPIENT)).toEqual(0n); + }); + + it('should fail when approve from zero', () => { + caller = ZERO; + + expect(() => { + token.approve(Z_SPENDER, AMOUNT, caller); + }).toThrow('ERC20: invalid owner'); + }); + + it('should fail when approve to zero', () => { + caller = OWNER; + + expect(() => { + token.approve(utils.ZERO_ADDRESS, AMOUNT, caller); + }).toThrow('ERC20: invalid spender'); + }); + + it('should transfer exact allowance and fail subsequent transfer', () => { + token._mint(Z_OWNER, AMOUNT); + caller = OWNER; + token.approve(Z_SPENDER, AMOUNT, caller); + + caller = SPENDER; + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, 1n, caller); + }).toThrow('ERC20: insufficient allowance'); + }); + + it('should allow approve of 0 tokens', () => { + caller = OWNER; + token.approve(Z_SPENDER, 0n, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + + it('should handle allowance with empty _allowances', () => { + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + }); + + describe('transferFrom', () => { + beforeEach(() => { + caller = OWNER; + + token.approve(Z_SPENDER, AMOUNT, caller); + token._mint(Z_OWNER, AMOUNT); + }); + + afterEach(() => { + expect(token.totalSupply()).toEqual(AMOUNT); + }); + + it('should transferFrom spender (partial)', () => { + caller = SPENDER; + const partialAmt = AMOUNT - 1n; + + const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, partialAmt, caller); + expect(txSuccess).toBeTruthy(); + + // Check balances + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); + // Check leftover allowance + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(1n); + }); + + it('should transferFrom spender (full)', () => { + caller = SPENDER; + + const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + expect(txSuccess).toBeTruthy(); + + // Check balances + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); + // Check no allowance + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + + it('should transferFrom and not consume infinite allowance', () => { + caller = OWNER; + token.approve(Z_SPENDER, MAX_UINT128, caller); + + caller = SPENDER; + const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + expect(txSuccess).toBeTruthy(); + + // Check balances + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); + // Check infinite allowance + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(MAX_UINT128); + }); + + it ('should fail when transfer amount exceeds allowance', () => { + caller = SPENDER; + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n); + }).toThrow('ERC20: insufficient allowance'); + }); + + it ('should fail when transfer amount exceeds balance', () => { + caller = OWNER; + // Increase allowance > balance + token.approve(Z_SPENDER, AMOUNT + 1n, caller); + + caller = SPENDER; + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n, caller); + }).toThrow('ERC20: insufficient balance'); + }); + + it('should fail when spender does not have allowance', () => { + caller = UNAUTHORIZED; + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + }).toThrow("ERC20: insufficient allowance"); + }); + + it('should fail to transferFrom zero address', () => { + caller = ZERO; + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + }).toThrow("ERC20: insufficient allowance"); + }); + + it('should fail to transferFrom to the zero address', () => { + caller = SPENDER; + + expect(() => { + token.transferFrom(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT, caller); + }).toThrow("ERC20: invalid receiver"); + }); + }); + + describe('_transfer', () => { + beforeEach(() => { + token._mint(Z_OWNER, AMOUNT); + }); + + afterEach(() => { + expect(token.totalSupply()).toEqual(AMOUNT); + }); + + it('should update balances (partial)', () => { + const partialAmt = AMOUNT - 1n; + token._transfer(Z_OWNER, Z_RECIPIENT, partialAmt); + + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); + }); + }) + + describe('_mint', () => { + it('should mint and update supply', () => { + expect(token.totalSupply()).toEqual(0n); + + token._mint(Z_RECIPIENT, AMOUNT); + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); + }); + + it('should catch mint overflow', () => { + token._mint(Z_RECIPIENT, MAX_UINT128); + + expect(() => { + token._mint(Z_RECIPIENT, 1n); + }).toThrow('ERC20: arithmetic overflow'); + }); + + it('should not mint to zero pubkey', () => { + expect(() => { + token._mint(utils.ZERO_KEY, AMOUNT); + }).toThrow('ERC20: invalid receiver'); + }); + + it('should not mint to zero contract address', () => { + expect(() => { + token._mint(utils.ZERO_ADDRESS, AMOUNT); + }).toThrow('ERC20: invalid receiver'); + }); + + it('should allow mint of 0 tokens', () => { + token._mint(Z_OWNER, 0n); + expect(token.totalSupply()).toEqual(0n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + }); + + describe('_burn', () => { + beforeEach(() => { + token._mint(Z_OWNER, AMOUNT); + }); + + it('should burn tokens', () => { + token._burn(Z_OWNER, 1n); + + const afterBurn = AMOUNT - 1n; + expect(token.balanceOf(Z_OWNER)).toEqual(afterBurn); + expect(token.totalSupply()).toEqual(afterBurn); + }); + + it('should throw when burning from zero', () => { + expect(() => { + token._burn(utils.ZERO_KEY, AMOUNT); + }).toThrow('ERC20: invalid sender'); + }); + + it('should throw when burn amount is greater than balance', () => { + expect(() => { + token._burn(Z_OWNER, AMOUNT + 1n); + }).toThrow('ERC20: insufficient balance'); + }); + + it('should allow burn of 0 tokens', () => { + token._burn(Z_OWNER, 0n); + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + }); + }); + + describe('_update', () => { + it('should update from zero to non-zero (mint)', () => { + expect(token.totalSupply()).toEqual(0n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + + token._update(utils.ZERO_KEY, Z_OWNER, AMOUNT); + + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + }); + + it('should catch overflow from zero to non-zero (mint)', () => { + token._update(utils.ZERO_KEY, Z_OWNER, MAX_UINT128); + + expect(() => { + token._update(utils.ZERO_KEY, Z_OWNER, 1n); + }).toThrow('ERC20: arithmetic overflow'); + }); + + describe('with minted tokens', () => { + beforeEach(() => { + token._update(utils.ZERO_ADDRESS, Z_OWNER, AMOUNT); + + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + }); + + it('should update from non-zero to zero (burn)', () => { + token._update(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); + + expect(token.totalSupply()).toEqual(0n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + + it('should catch overflow from non-zero to zero (burn)', () => { + token._update(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); + + expect(() => { + token._update(Z_OWNER, utils.ZERO_ADDRESS, 1n); + }).toThrow('ERC20: insufficient balance'); + }); + + it('should update from non-zero to non-zero (transfer)', () => { + token._update(Z_OWNER, Z_RECIPIENT, AMOUNT - 1n); + + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); + }); + }); + }); + + describe('Multiple Operations', () => { + it('should handle mint → transfer → burn sequence', () => { + token._mint(Z_OWNER, AMOUNT); + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + + caller = OWNER; + token.transfer(Z_RECIPIENT, AMOUNT - 1n, caller); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); + + token._burn(Z_OWNER, 1n); + expect(token.totalSupply()).toEqual(AMOUNT - 1n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + }); +}); diff --git a/contracts/utils/.eslintignore b/contracts/utils/.eslintignore new file mode 100644 index 00000000..327555cd --- /dev/null +++ b/contracts/utils/.eslintignore @@ -0,0 +1 @@ +src/artifacts diff --git a/contracts/utils/.eslintrc.cjs b/contracts/utils/.eslintrc.cjs new file mode 100644 index 00000000..581f1d49 --- /dev/null +++ b/contracts/utils/.eslintrc.cjs @@ -0,0 +1,30 @@ +module.exports = { + env: { + browser: true, + es2021: true, + node: true, + jest: true, + }, + extends: [ + 'standard-with-typescript', + 'plugin:prettier/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + ], + overrides: [], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['tsconfig.json'], + }, + rules: { + '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 + '@typescript-eslint/no-floating-promises': 'warn', + '@typescript-eslint/promise-function-async': 'off', + '@typescript-eslint/no-redeclare': 'off', + '@typescript-eslint/no-invalid-void-type': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/consistent-type-definitions': 'off' + }, +}; diff --git a/contracts/utils/js-resolver.cjs b/contracts/utils/js-resolver.cjs new file mode 100644 index 00000000..cc9ed285 --- /dev/null +++ b/contracts/utils/js-resolver.cjs @@ -0,0 +1,16 @@ +const jsResolver = (path, options) => { + const jsExtRegex = /\.js$/i + const resolver = options.defaultResolver + if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { + const newPath = path.replace(jsExtRegex, '.ts'); + try { + return resolver(newPath, options) + } catch { + // use default resolver + } + } + + return resolver(path, options) +} + +module.exports = jsResolver diff --git a/contracts/utils/package.json b/contracts/utils/package.json new file mode 100644 index 00000000..d914daf0 --- /dev/null +++ b/contracts/utils/package.json @@ -0,0 +1,32 @@ +{ + "name": "@openzeppelin-midnight-contracts/erc20-contract", + "type": "module", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "scripts": { + "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", + "test": "NODE_OPTIONS=--experimental-vm-modules jest", + "prepack": "yarn build", + "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/ERC20.compact ./dist", + "lint": "eslint src", + "typecheck": "tsc -p tsconfig.json --noEmit" + }, + "dependencies": { + "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" + }, + "devDependencies": { + "@midnight-ntwrk/compact": "workspace:*", + "eslint": "^8.52.0", + "jest": "^29.7.0", + "typescript": "^5.2.2" + } +} diff --git a/contracts/utils/tsconfig.build.json b/contracts/utils/tsconfig.build.json new file mode 100644 index 00000000..f1132509 --- /dev/null +++ b/contracts/utils/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["src/test/**/*.ts"], + "compilerOptions": {} +} diff --git a/contracts/utils/tsconfig.json b/contracts/utils/tsconfig.json new file mode 100644 index 00000000..3e90b0a9 --- /dev/null +++ b/contracts/utils/tsconfig.json @@ -0,0 +1,21 @@ +{ + "include": ["src/**/*.ts"], + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "lib": ["ESNext"], + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "node", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": true, + "strict": true, + "isolatedModules": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true + } +} diff --git a/yarn.lock b/yarn.lock index 828e66a0..bcbcaf4b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1114,6 +1114,7 @@ __metadata: resolution: "@openzeppelin-midnight-contracts/initializable-contract@workspace:contracts/initializable" dependencies: "@midnight-ntwrk/compact": "workspace:*" + "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" eslint: "npm:^8.52.0" jest: "npm:^29.7.0" typescript: "npm:^5.2.2" From 43f5eac963c6dda5a057bbd03a93c2a0447fd1a8 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 14:34:03 -0400 Subject: [PATCH 043/282] refactor _requireOwned --- contracts/erc721/src/ERC721.compact | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index ad36536c..c9f53ba5 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -82,17 +82,14 @@ module ERC721 { } circuit _requireOwned(tokenId: Field): Either { - const owner = _ownerOf(tokenId); + assert _owners.member(tokenId) "ERC721: Nonexistent Token"; + const owner = _owners.lookup(tokenId); + assert !Utils_isKeyOrAddressZero(owner) "ERC721: Invalid Owner"; return owner; } circuit _ownerOf(tokenId: Field): Either { - if (!_owners.member(tokenId)) { - // If tokenId doesn't exist, create and insert a default value - // What is default value?? - _owners.insert(tokenId, default>); - } return _owners.lookup(tokenId); } From 958fcf1d05031249a0acfcb2d0b9adc9a3b2ccd9 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 15:06:13 -0400 Subject: [PATCH 044/282] adds safeTransferFrom function signatures --- contracts/erc721/src/ERC721.compact | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index c9f53ba5..20f5e55b 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -195,5 +195,24 @@ module ERC721 { return _tokenApprovals.lookup(tokenId); } + + export circuit safeTransferFrom( + from: Either, + to: Either, + tokenId: Field + ): [] { + safeTransferFrom(from, to, tokenId, ""); + } + + export circuit safeTransferFrom( + from: Either, + to: Either, + tokenId: Field, + data: Opaque<"string"> + ): [] { + transferFrom(from, to, tokenId); + // TODO: Impl rest + } + } From c8ada5789169ee419eb622b9162f6bda2a62ebc6 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 16:42:38 -0400 Subject: [PATCH 045/282] updates `_approve` signature --- contracts/erc721/src/ERC721.compact | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 20f5e55b..43f69707 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -143,17 +143,12 @@ module ERC721 { to: Either, tokenId: Field, auth: Either, - emitEvent: Boolean ): [] { - if (emitEvent || !Utils_isKeyOrAddressZero(auth)) { + if (!Utils_isKeyOrAddressZero(auth)) { owner = _requireOwned(tokenId); // We do not use _isAuthorized because single-token approvals should not be able to call approve - assert (!Utils_isKeyOrAddressZero(auth) && owner != auth && !isApprovedForAll(owner, auth)) "ERC721 Invalid Approver" - - // if (emitEvent) { - // impl event here when available - // } + assert (!Utils_isKeyOrAddressZero(auth) && owner != auth && !isApprovedForAll(owner, auth)) "ERC721 Invalid Approver"; } _tokenApprovals.insert(tokenId, to); @@ -211,8 +206,11 @@ module ERC721 { data: Opaque<"string"> ): [] { transferFrom(from, to, tokenId); - // TODO: Impl rest + // See https://github.com/OpenZeppelin/midnight-contracts/issues/25 + // ERC721Utils_checkOnERC721Received } + + } From b5b78dd391f317cf9bb871e17161b99432a4e0d9 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 17:35:28 -0400 Subject: [PATCH 046/282] Add setApprovalForAll fn --- contracts/erc721/src/ERC721.compact | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 43f69707..29266fc5 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -210,7 +210,29 @@ module ERC721 { // ERC721Utils_checkOnERC721Received } - - + export circuit setApprovalForAll( + operator: Either, + approved: Boolean + ): [] { + _setApprovalForAll(own_public_key(), operator, approved); + } + + circuit _setApprovalForAll( + owner: Either, + operator: Either, + approved: Boolean + ): [] { + assert !Utils_isKeyOrAddressZero(operator) "ERC721: Invalid Operator"; + + if (!_operatorApprovals.member(owner)) { + _operatorApprovals.insert( + owner, + default, Boolean>> + ); + _operatorApprovals.lookup(owner).insert(operator, approved); + } else { + _operatorApprovals.lookup(owner).insert(operator, approved); + } + } } From 87d364d063115ece1be2b5020b175a67a66d03d3 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 17:39:49 -0400 Subject: [PATCH 047/282] adds getApproved fn --- contracts/erc721/src/ERC721.compact | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 29266fc5..b4e4c41d 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -234,5 +234,12 @@ module ERC721 { _operatorApprovals.lookup(owner).insert(operator, approved); } } + + export circuit getApproved(tokenId: Field) { + _requireOwned(tokenId); + + return _getApproved(tokenId); + } + } From e30440dc094bf7263c24b573ff5e7848f9558c7c Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 17:42:32 -0400 Subject: [PATCH 048/282] add approve fn --- contracts/erc721/src/ERC721.compact | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index b4e4c41d..a242903f 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -241,5 +241,13 @@ module ERC721 { return _getApproved(tokenId); } + export circuit approve( + to: Either, + tokenId: Field + ): [] { + _approve(to, tokenId, own_public_key()); + } + + } From ea7a727e3a41a6c05b3b145337a0ee6018b66c3e Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 18:01:24 -0400 Subject: [PATCH 049/282] Add tokenURI fn --- contracts/erc721/src/ERC721.compact | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index a242903f..2980bfcb 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -28,6 +28,9 @@ module ERC721 { export ledger _tokenApprovals: Map>; export ledger _operatorApprovals: Map, Map, Boolean>>; + /// Private state + witness computeTokenURI(baseURI: Opaque<"string">): Opaque; + /** * @description Initializes the contract by setting the name and symbol. * @@ -248,6 +251,17 @@ module ERC721 { _approve(to, tokenId, own_public_key()); } + export circuit tokenURI(tokenId: Field): Opaque<"string"> { + _requireOwned(tokenId); + + const baseURI = _baseURI(); + return computeTokenURI(baseURI); + } + + circuit _baseURI(): Opaque<"string"> { + return ""; + } + } From 531acbf84eac7fd3ed336b1761593ccd28492db4 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 18:23:14 -0400 Subject: [PATCH 050/282] Adds _increaseBalance fn --- contracts/erc721/src/ERC721.compact | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 2980bfcb..592b17d1 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -80,6 +80,14 @@ module ERC721 { return _balances.lookup(account); } + /** + * @description Returns the owner of the `tokenId` token. + * + * @dev Tokens assigned to zero address are considered invalid, and queries about them do throw. + * + * @param {tokenId} - The identifier for a token. + * @return {Either} - The public key or contract that owns the token. + */ export circuit ownerOf(tokenId: Field): Either { return _requireOwned(tokenId); } @@ -262,6 +270,12 @@ module ERC721 { return ""; } - + circuit _increaseBalance( + account: Either, + value: Uint<128> + ): [] { + const newValue = _balances.lookup(account) + value; + _balances.insert(account, newValue); + } } From a0ca09652bc05c0b6b47fd51c83ae79c8946e3b9 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 18:28:22 -0400 Subject: [PATCH 051/282] Fix compile error in `_update` --- contracts/erc721/src/ERC721.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 592b17d1..87c21ddf 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -124,7 +124,7 @@ module ERC721 { tokenId: Field, auth: Either ): Either { - from = _ownerOf(tokenId); + const from = _ownerOf(tokenId); // Perform (optional) operator check if (!Utils_isKeyOrAddressZero(auth)) { From b9f1effd4d69b0e96c7122f13267a7d3b6faea14 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 18:37:48 -0400 Subject: [PATCH 052/282] adds _mint fn --- contracts/erc721/src/ERC721.compact | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 87c21ddf..e0e42baa 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -277,5 +277,18 @@ module ERC721 { const newValue = _balances.lookup(account) + value; _balances.insert(account, newValue); } + + circuit _mint( + to: Either, + tokenId: Field + ): [] { + assert !Utils_isKeyOrAddressZero(to) "ERC721: Invald Receiver" + + // Assumes burn_address == zero address + // May want to define as default + const previousOwner = _update(to, tokenId, burn_address()); + + assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Invalid Sender" + } } From 6de8a59e3df13478f756a9e6e48ff2fa465ad2dd Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 18:44:50 -0400 Subject: [PATCH 053/282] Add _safeMint fn --- contracts/erc721/src/ERC721.compact | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index e0e42baa..7366a217 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -290,5 +290,21 @@ module ERC721 { assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Invalid Sender" } + + circuit _safeMint( + to: Either, + tokenId: Field + ): [] { + _safeMint(to, tokenId, ""); + } + + circuit _safeMint( + to: Either, + tokenId: Field, + data: Opaque<"string"> + ): [] { + _mint(to, tokenId); + // ERC721Utils_checkOnERC721Received + } } From 717215c09971976cceb565f2ad1b60f07566ecb6 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 18:48:47 -0400 Subject: [PATCH 054/282] Add _burn fn --- contracts/erc721/src/ERC721.compact | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 7366a217..41604ab5 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -306,5 +306,10 @@ module ERC721 { _mint(to, tokenId); // ERC721Utils_checkOnERC721Received } + + circuit _burn(tokenId: Field): [] { + const previousOwner = _update(burn_address(), tokenId, burn_address()); + assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Nonexistent Token"; + } } From 14b4aa6d45f0d2764956beba5f2d315704bcd70f Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 9 Apr 2025 19:02:24 -0400 Subject: [PATCH 055/282] Add _transfer fn --- contracts/erc721/src/ERC721.compact | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 41604ab5..cb6a3188 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -311,5 +311,18 @@ module ERC721 { const previousOwner = _update(burn_address(), tokenId, burn_address()); assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Nonexistent Token"; } + + circuit _transfer( + from: Either, + to: Either, + tokenId: Field + ): [] { + assert !Utils_isKeyOrAddressZero(to) "ERC721: Invalid Receiver" + + const previousOwner = _update(to, tokenId, burn_address()); + + assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Nonexistent Token" + assert previousOwner != from "ERC721: Incorrect Owner" + } } From b627dbe5d885b8f4858a1d0877c1993f1fbf952b Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Thu, 10 Apr 2025 13:42:38 -0400 Subject: [PATCH 056/282] Fix compiler errors --- contracts/erc721/src/ERC721.compact | 60 +++++++++++++++++------------ 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index cb6a3188..f215dda2 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -29,7 +29,7 @@ module ERC721 { export ledger _operatorApprovals: Map, Map, Boolean>>; /// Private state - witness computeTokenURI(baseURI: Opaque<"string">): Opaque; + witness computeTokenURI(baseURI: Opaque<"string">): Opaque<"string">; /** * @description Initializes the contract by setting the name and symbol. @@ -115,7 +115,11 @@ module ERC721 { // Assumes sender is a ZSwapPublicKey // Need to revisit once we have contract <> contract communication - const previousOwner = _update(to, tokenId, own_public_key()); + const previousOwner = _update( + to, + tokenId, + left(own_public_key()) + ); assert previousOwner != from "ERC721: Incorrect Owner"; } @@ -135,14 +139,14 @@ module ERC721 { if (!Utils_isKeyOrAddressZero(from)) { // assuming burn address == zero address // Need to test to confirm - _approve(burn_address(), tokenId, burn_address(), false); + _approve(burn_address(), tokenId, burn_address()); const newBalance = _balances.lookup(from) - 1 as Uint<128>; - _balances.insert(tokenId, newBalance); + _balances.insert(from, newBalance); } if (!Utils_isKeyOrAddressZero(to)) { const newBalance = _balances.lookup(to) + 1 as Uint<128>; - _balances.insert(tokenId, newBalance); + _balances.insert(to, newBalance); } _owners.insert(tokenId, to); @@ -153,10 +157,10 @@ module ERC721 { circuit _approve( to: Either, tokenId: Field, - auth: Either, + auth: Either ): [] { if (!Utils_isKeyOrAddressZero(auth)) { - owner = _requireOwned(tokenId); + const owner = _requireOwned(tokenId); // We do not use _isAuthorized because single-token approvals should not be able to call approve assert (!Utils_isKeyOrAddressZero(auth) && owner != auth && !isApprovedForAll(owner, auth)) "ERC721 Invalid Approver"; @@ -171,8 +175,8 @@ module ERC721 { tokenId: Field ): [] { if (!_isAuthorized(owner, spender, tokenId)) { - assert !Utils_isKeyOrAddressZero(owner) "ERC721: Nonexistent Token" - assert false "ERC721: Insufficient Approval" + assert !Utils_isKeyOrAddressZero(owner) "ERC721: Nonexistent Token"; + assert false "ERC721: Insufficient Approval"; } } @@ -181,15 +185,15 @@ module ERC721 { spender: Either, tokenId: Field ): Boolean { - return !Utils_isKeyOrAddressZero(spender) && (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender) + return (!Utils_isKeyOrAddressZero(spender) && (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender)); } export circuit isApprovedForAll( owner: Either, operator: Either ): Boolean { - if (_operatorApprovals.member(owner) && _operatorApprovals.lookup(owner).member(spender)) { - return _operatorApprovals.lookup(owner).lookup(spender); + if (_operatorApprovals.member(owner) && _operatorApprovals.lookup(owner).member(operator)) { + return _operatorApprovals.lookup(owner).lookup(operator); } else { return false; } @@ -207,7 +211,7 @@ module ERC721 { to: Either, tokenId: Field ): [] { - safeTransferFrom(from, to, tokenId, ""); + safeTransferFrom(from, to, tokenId, default>); } export circuit safeTransferFrom( @@ -225,7 +229,11 @@ module ERC721 { operator: Either, approved: Boolean ): [] { - _setApprovalForAll(own_public_key(), operator, approved); + _setApprovalForAll( + left(own_public_key()), + operator, + approved + ); } circuit _setApprovalForAll( @@ -246,7 +254,7 @@ module ERC721 { } } - export circuit getApproved(tokenId: Field) { + export circuit getApproved(tokenId: Field): Either { _requireOwned(tokenId); return _getApproved(tokenId); @@ -256,7 +264,11 @@ module ERC721 { to: Either, tokenId: Field ): [] { - _approve(to, tokenId, own_public_key()); + _approve( + to, + tokenId, + left(own_public_key()) + ); } export circuit tokenURI(tokenId: Field): Opaque<"string"> { @@ -267,7 +279,7 @@ module ERC721 { } circuit _baseURI(): Opaque<"string"> { - return ""; + return default>; } circuit _increaseBalance( @@ -275,27 +287,27 @@ module ERC721 { value: Uint<128> ): [] { const newValue = _balances.lookup(account) + value; - _balances.insert(account, newValue); + _balances.insert(account, newValue as Uint<128>); } circuit _mint( to: Either, tokenId: Field ): [] { - assert !Utils_isKeyOrAddressZero(to) "ERC721: Invald Receiver" + assert !Utils_isKeyOrAddressZero(to) "ERC721: Invald Receiver"; // Assumes burn_address == zero address // May want to define as default const previousOwner = _update(to, tokenId, burn_address()); - assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Invalid Sender" + assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Invalid Sender"; } circuit _safeMint( to: Either, tokenId: Field ): [] { - _safeMint(to, tokenId, ""); + _safeMint(to, tokenId, default>); } circuit _safeMint( @@ -317,12 +329,12 @@ module ERC721 { to: Either, tokenId: Field ): [] { - assert !Utils_isKeyOrAddressZero(to) "ERC721: Invalid Receiver" + assert !Utils_isKeyOrAddressZero(to) "ERC721: Invalid Receiver"; const previousOwner = _update(to, tokenId, burn_address()); - assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Nonexistent Token" - assert previousOwner != from "ERC721: Incorrect Owner" + assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Nonexistent Token"; + assert previousOwner != from "ERC721: Incorrect Owner"; } } From 2a3d27f3be0e22c6d4fca97361d2c26add3122cf Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Thu, 10 Apr 2025 13:49:16 -0400 Subject: [PATCH 057/282] reorg code --- contracts/erc721/src/ERC721.compact | 149 ++++++++++++++-------------- 1 file changed, 76 insertions(+), 73 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index f215dda2..8d688346 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -92,16 +92,54 @@ module ERC721 { return _requireOwned(tokenId); } - circuit _requireOwned(tokenId: Field): Either { - assert _owners.member(tokenId) "ERC721: Nonexistent Token"; - const owner = _owners.lookup(tokenId); + export circuit tokenURI(tokenId: Field): Opaque<"string"> { + _requireOwned(tokenId); - assert !Utils_isKeyOrAddressZero(owner) "ERC721: Invalid Owner"; - return owner; + const baseURI = _baseURI(); + return computeTokenURI(baseURI); } - circuit _ownerOf(tokenId: Field): Either { - return _owners.lookup(tokenId); + circuit _baseURI(): Opaque<"string"> { + return default>; + } + + export circuit approve( + to: Either, + tokenId: Field + ): [] { + _approve( + to, + tokenId, + left(own_public_key()) + ); + } + + export circuit getApproved(tokenId: Field): Either { + _requireOwned(tokenId); + + return _getApproved(tokenId); + } + + export circuit setApprovalForAll( + operator: Either, + approved: Boolean + ): [] { + _setApprovalForAll( + left(own_public_key()), + operator, + approved + ); + } + + export circuit isApprovedForAll( + owner: Either, + operator: Either + ): Boolean { + if (_operatorApprovals.member(owner) && _operatorApprovals.lookup(owner).member(operator)) { + return _operatorApprovals.lookup(owner).lookup(operator); + } else { + return false; + } } export circuit transferFrom( @@ -123,6 +161,37 @@ module ERC721 { assert previousOwner != from "ERC721: Incorrect Owner"; } + circuit _requireOwned(tokenId: Field): Either { + assert _owners.member(tokenId) "ERC721: Nonexistent Token"; + const owner = _owners.lookup(tokenId); + + assert !Utils_isKeyOrAddressZero(owner) "ERC721: Invalid Owner"; + return owner; + } + + circuit _ownerOf(tokenId: Field): Either { + return _owners.lookup(tokenId); + } + + export circuit safeTransferFrom( + from: Either, + to: Either, + tokenId: Field + ): [] { + safeTransferFrom(from, to, tokenId, default>); + } + + export circuit safeTransferFrom( + from: Either, + to: Either, + tokenId: Field, + data: Opaque<"string"> + ): [] { + transferFrom(from, to, tokenId); + // See https://github.com/OpenZeppelin/midnight-contracts/issues/25 + // ERC721Utils_checkOnERC721Received + } + circuit _update( to: Either, tokenId: Field, @@ -188,54 +257,12 @@ module ERC721 { return (!Utils_isKeyOrAddressZero(spender) && (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender)); } - export circuit isApprovedForAll( - owner: Either, - operator: Either - ): Boolean { - if (_operatorApprovals.member(owner) && _operatorApprovals.lookup(owner).member(operator)) { - return _operatorApprovals.lookup(owner).lookup(operator); - } else { - return false; - } - } - circuit _getApproved(tokenId: Field): Either { // I think this returns the 0 address if token doesn't exist // Make sure this doesn't cause problem in testing return _tokenApprovals.lookup(tokenId); } - - export circuit safeTransferFrom( - from: Either, - to: Either, - tokenId: Field - ): [] { - safeTransferFrom(from, to, tokenId, default>); - } - - export circuit safeTransferFrom( - from: Either, - to: Either, - tokenId: Field, - data: Opaque<"string"> - ): [] { - transferFrom(from, to, tokenId); - // See https://github.com/OpenZeppelin/midnight-contracts/issues/25 - // ERC721Utils_checkOnERC721Received - } - - export circuit setApprovalForAll( - operator: Either, - approved: Boolean - ): [] { - _setApprovalForAll( - left(own_public_key()), - operator, - approved - ); - } - circuit _setApprovalForAll( owner: Either, operator: Either, @@ -254,33 +281,9 @@ module ERC721 { } } - export circuit getApproved(tokenId: Field): Either { - _requireOwned(tokenId); - return _getApproved(tokenId); - } - export circuit approve( - to: Either, - tokenId: Field - ): [] { - _approve( - to, - tokenId, - left(own_public_key()) - ); - } - - export circuit tokenURI(tokenId: Field): Opaque<"string"> { - _requireOwned(tokenId); - const baseURI = _baseURI(); - return computeTokenURI(baseURI); - } - - circuit _baseURI(): Opaque<"string"> { - return default>; - } circuit _increaseBalance( account: Either, From abdf0dc2b032e846b3c26e50558ee15875c5cf11 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Thu, 10 Apr 2025 14:00:22 -0400 Subject: [PATCH 058/282] Adds `baseURI` witness to interface --- contracts/erc721/src/ERC721.compact | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 8d688346..9779fa11 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -30,6 +30,7 @@ module ERC721 { /// Private state witness computeTokenURI(baseURI: Opaque<"string">): Opaque<"string">; + witness baseURI(): Opaque<"string">; /** * @description Initializes the contract by setting the name and symbol. From 9cdc6603d1c67e4f0de89f5f8339c461775750e9 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Thu, 10 Apr 2025 15:41:03 -0400 Subject: [PATCH 059/282] export circuits for testing --- contracts/erc721/src/ERC721.compact | 40 +++++++++++++---------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 9779fa11..eee96add 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -30,7 +30,7 @@ module ERC721 { /// Private state witness computeTokenURI(baseURI: Opaque<"string">): Opaque<"string">; - witness baseURI(): Opaque<"string">; + export witness baseURI(): Opaque<"string">; /** * @description Initializes the contract by setting the name and symbol. @@ -97,10 +97,10 @@ module ERC721 { _requireOwned(tokenId); const baseURI = _baseURI(); - return computeTokenURI(baseURI); + return disclose(computeTokenURI(baseURI)); } - circuit _baseURI(): Opaque<"string"> { + export circuit _baseURI(): Opaque<"string"> { return default>; } @@ -162,7 +162,7 @@ module ERC721 { assert previousOwner != from "ERC721: Incorrect Owner"; } - circuit _requireOwned(tokenId: Field): Either { + export circuit _requireOwned(tokenId: Field): Either { assert _owners.member(tokenId) "ERC721: Nonexistent Token"; const owner = _owners.lookup(tokenId); @@ -170,7 +170,7 @@ module ERC721 { return owner; } - circuit _ownerOf(tokenId: Field): Either { + export circuit _ownerOf(tokenId: Field): Either { return _owners.lookup(tokenId); } @@ -193,7 +193,7 @@ module ERC721 { // ERC721Utils_checkOnERC721Received } - circuit _update( + export circuit _update( to: Either, tokenId: Field, auth: Either @@ -224,7 +224,7 @@ module ERC721 { return from; } - circuit _approve( + export circuit _approve( to: Either, tokenId: Field, auth: Either @@ -239,7 +239,7 @@ module ERC721 { _tokenApprovals.insert(tokenId, to); } - circuit _checkAuthorized( + export circuit _checkAuthorized( owner: Either, spender: Either, tokenId: Field @@ -250,7 +250,7 @@ module ERC721 { } } - circuit _isAuthorized( + export circuit _isAuthorized( owner: Either, spender: Either, tokenId: Field @@ -258,13 +258,13 @@ module ERC721 { return (!Utils_isKeyOrAddressZero(spender) && (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender)); } - circuit _getApproved(tokenId: Field): Either { + export circuit _getApproved(tokenId: Field): Either { // I think this returns the 0 address if token doesn't exist // Make sure this doesn't cause problem in testing return _tokenApprovals.lookup(tokenId); } - circuit _setApprovalForAll( + export circuit _setApprovalForAll( owner: Either, operator: Either, approved: Boolean @@ -281,12 +281,8 @@ module ERC721 { _operatorApprovals.lookup(owner).insert(operator, approved); } } - - - - - - circuit _increaseBalance( + + export circuit _increaseBalance( account: Either, value: Uint<128> ): [] { @@ -294,7 +290,7 @@ module ERC721 { _balances.insert(account, newValue as Uint<128>); } - circuit _mint( + export circuit _mint( to: Either, tokenId: Field ): [] { @@ -307,14 +303,14 @@ module ERC721 { assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Invalid Sender"; } - circuit _safeMint( + export circuit _safeMint( to: Either, tokenId: Field ): [] { _safeMint(to, tokenId, default>); } - circuit _safeMint( + export circuit _safeMint( to: Either, tokenId: Field, data: Opaque<"string"> @@ -323,12 +319,12 @@ module ERC721 { // ERC721Utils_checkOnERC721Received } - circuit _burn(tokenId: Field): [] { + export circuit _burn(tokenId: Field): [] { const previousOwner = _update(burn_address(), tokenId, burn_address()); assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Nonexistent Token"; } - circuit _transfer( + export circuit _transfer( from: Either, to: Either, tokenId: Field From 30e8b93fb8e7d6cb7c01f695b415ddc56c514475 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Thu, 10 Apr 2025 15:46:56 -0400 Subject: [PATCH 060/282] reorg code --- contracts/erc721/src/ERC721.compact | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index eee96add..03b88d9d 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -162,18 +162,6 @@ module ERC721 { assert previousOwner != from "ERC721: Incorrect Owner"; } - export circuit _requireOwned(tokenId: Field): Either { - assert _owners.member(tokenId) "ERC721: Nonexistent Token"; - const owner = _owners.lookup(tokenId); - - assert !Utils_isKeyOrAddressZero(owner) "ERC721: Invalid Owner"; - return owner; - } - - export circuit _ownerOf(tokenId: Field): Either { - return _owners.lookup(tokenId); - } - export circuit safeTransferFrom( from: Either, to: Either, @@ -193,6 +181,18 @@ module ERC721 { // ERC721Utils_checkOnERC721Received } + export circuit _requireOwned(tokenId: Field): Either { + assert _owners.member(tokenId) "ERC721: Nonexistent Token"; + const owner = _owners.lookup(tokenId); + + assert !Utils_isKeyOrAddressZero(owner) "ERC721: Invalid Owner"; + return owner; + } + + export circuit _ownerOf(tokenId: Field): Either { + return _owners.lookup(tokenId); + } + export circuit _update( to: Either, tokenId: Field, From 5d9b2eb032090ae73d7d460530d813dd9a9a2e24 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Thu, 10 Apr 2025 15:58:53 -0400 Subject: [PATCH 061/282] Add all mock functions --- .../erc721/src/test/mocks/MockERC721.compact | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/contracts/erc721/src/test/mocks/MockERC721.compact b/contracts/erc721/src/test/mocks/MockERC721.compact index 8060593f..33aefcb0 100644 --- a/contracts/erc721/src/test/mocks/MockERC721.compact +++ b/contracts/erc721/src/test/mocks/MockERC721.compact @@ -29,4 +29,152 @@ export circuit balanceOf(account: Either): export circuit ownerOf(tokenId: Field): Either { return ERC721_ownerOf(tokenId); +} + +export circuit tokenURI(tokenId: Field): Opaque<"string"> { + return ERC721_tokenURI(tokenId); +} + +export circuit approve( + to: Either, + tokenId: Field +): [] { + return ERC721_approve(to, tokenId); +} + +export circuit getApproved(tokenId: Field): Either { + return ERC721_getApproved(tokenId); +} + +export circuit setApprovalForAll( + operator: Either, + approved: Boolean +): [] { + return ERC721_setApprovalForAll(operator, approved); +} + +export circuit isApprovedForAll( + owner: Either, + operator: Either +): Boolean { + return ERC721_isApprovedForAll(owner, operator); +} + +export circuit transferFrom( + from: Either, + to: Either, + tokenId: Field +): [] { + return ERC721_transferFrom(from, to, tokenId); +} + +export circuit safeTransferFrom( + from: Either, + to: Either, + tokenId: Field +): [] { + return ERC721_safeTransferFrom(from, to, tokenId); +} + +export circuit safeTransferFrom( + from: Either, + to: Either, + tokenId: Field, + data: Opaque<"string"> +): [] { + return ERC721_safeTransferFrom(from, to, tokenId, data); +} + +export circuit _requireOwned(tokenId: Field): Either { + return ERC721__requireOwned(tokenId); +} + +export circuit _ownerOf(tokenId: Field): Either { + return ERC721__ownerOf(tokenId); +} + +export circuit _update( + to: Either, + tokenId: Field, + auth: Either +): Either { + return ERC721__update(to, tokenId, auth); +} + +export circuit _approve( + to: Either, + tokenId: Field, + auth: Either +): [] { + return ERC721__approve(to, tokenId, auth); +} + +export circuit _checkAuthorized( + owner: Either, + spender: Either, + tokenId: Field +): [] { + return ERC721__checkAuthorized(owner, spender, tokenId); +} + +export circuit _isAuthorized( + owner: Either, + spender: Either, + tokenId: Field +): Boolean { + return ERC721__isAuthorized(owner, spender, tokenId); +} + + +export circuit _getApproved(tokenId: Field): Either { + return ERC721__getApproved(tokenId); +} + +export circuit _setApprovalForAll( + owner: Either, + operator: Either, + approved: Boolean +): [] { + return ERC721__setApprovalForAll(owner, operator, approved); +} + +export circuit _increaseBalance( + account: Either, + value: Uint<128> +): [] { + return ERC721__increaseBalance(account, value); +} + +export circuit _mint( + to: Either, + tokenId: Field +): [] { + return ERC721__mint(to, tokenId); +} + +export circuit _safeMint( + to: Either, + tokenId: Field +): [] { + return ERC721__safeMint(to, tokenId); +} + +export circuit _safeMint( + to: Either, + tokenId: Field, + data: Opaque<"string"> +): [] { + return ERC721__safeMint(to, tokenId, data); +} + +export circuit _burn(tokenId: Field): [] { + return ERC271__burn(tokenId); +} + +export circuit _transfer( + from: Either, + to: Either, + tokenId: Field +): [] { + return ERC721__transfer(from, to, tokenId); } \ No newline at end of file From 0177c0f29295f9628988ee2fa6a41a24a83a3df1 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Thu, 10 Apr 2025 16:31:27 -0400 Subject: [PATCH 062/282] Fix top-level export error --- contracts/erc721/src/test/mocks/MockERC721.compact | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contracts/erc721/src/test/mocks/MockERC721.compact b/contracts/erc721/src/test/mocks/MockERC721.compact index 33aefcb0..1c8643ff 100644 --- a/contracts/erc721/src/test/mocks/MockERC721.compact +++ b/contracts/erc721/src/test/mocks/MockERC721.compact @@ -76,7 +76,8 @@ export circuit safeTransferFrom( return ERC721_safeTransferFrom(from, to, tokenId); } -export circuit safeTransferFrom( +// Two functions with the same name are not allowed as top-level exports +export circuit _safeTransferFrom( from: Either, to: Either, tokenId: Field, @@ -159,7 +160,9 @@ export circuit _safeMint( return ERC721__safeMint(to, tokenId); } -export circuit _safeMint( + +// Two functions with the same name are not allowed as top-level exports +export circuit __safeMint( to: Either, tokenId: Field, data: Opaque<"string"> From 9e469991b58539779f362fee32b27d758d13f49b Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Thu, 10 Apr 2025 17:30:42 -0400 Subject: [PATCH 063/282] Fix name bug --- contracts/erc721/src/test/mocks/MockERC721.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/erc721/src/test/mocks/MockERC721.compact b/contracts/erc721/src/test/mocks/MockERC721.compact index 1c8643ff..77592a13 100644 --- a/contracts/erc721/src/test/mocks/MockERC721.compact +++ b/contracts/erc721/src/test/mocks/MockERC721.compact @@ -171,7 +171,7 @@ export circuit __safeMint( } export circuit _burn(tokenId: Field): [] { - return ERC271__burn(tokenId); + return ERC721__burn(tokenId); } export circuit _transfer( From 68c43faa57478e330f6ca2547c1908dc6749a179 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Thu, 10 Apr 2025 17:54:44 -0400 Subject: [PATCH 064/282] add yarn.lock --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index bcbcaf4b..4ae6fb7c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1097,9 +1097,9 @@ __metadata: languageName: unknown linkType: soft -"@openzeppelin-midnight-contracts/erc721-contract@workspace:contracts/erc721/contract": +"@openzeppelin-midnight-contracts/erc721-contract@workspace:contracts/erc721": version: 0.0.0-use.local - resolution: "@openzeppelin-midnight-contracts/erc721-contract@workspace:contracts/erc721/contract" + resolution: "@openzeppelin-midnight-contracts/erc721-contract@workspace:contracts/erc721" dependencies: "@midnight-ntwrk/compact": "workspace:*" "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" @@ -1109,7 +1109,7 @@ __metadata: languageName: unknown linkType: soft -"@openzeppelin-midnight-contracts/initializable-contract@workspace:contracts/initializable/contract": +"@openzeppelin-midnight-contracts/initializable-contract@workspace:contracts/initializable": version: 0.0.0-use.local resolution: "@openzeppelin-midnight-contracts/initializable-contract@workspace:contracts/initializable" dependencies: From 9aa56ce67627d887b2cabb328af786448c633738 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Fri, 25 Apr 2025 16:19:19 -0400 Subject: [PATCH 065/282] Adds new Util function --- contracts/utils/src/MockUtils.compact | 7 +++++++ contracts/utils/src/Utils.compact | 21 +++++++++++++++++++++ contracts/utils/src/test/UtilsSimulator.ts | 19 +++++++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/contracts/utils/src/MockUtils.compact b/contracts/utils/src/MockUtils.compact index f2263768..27e61500 100644 --- a/contracts/utils/src/MockUtils.compact +++ b/contracts/utils/src/MockUtils.compact @@ -11,3 +11,10 @@ export { ZswapCoinPublicKey, ContractAddress, Either }; export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { return Utils_isKeyOrAddressZero(keyOrAddress); } + +export pure circuit isKeyOrAddressEqual( + keyOrAddress: Either, + other: Either +): Boolean { + return Utils_isKeyOrAddressEqual(keyOrAddress, other); +} diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index acb02784..a14bd91a 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -24,4 +24,25 @@ module Utils { return keyOrAddress == right(ContractAddress{ zero }); } } + + /** + * @description Returns whether `keyOrAddress` is equal to `other`. Assumes that a ZswapCoinPublicKey + * and a ContractAddress can never be equal + * + * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @param {other} - The other value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @return {Boolean} - Returns true if `keyOrAddress` is is equal to `other`. + */ + export pure circuit isKeyOrAddressEqual( + keyOrAddress: Either, + other: Either + ): Boolean { + if (keyOrAddress.is_left && other.is_left) { + return keyOrAddress.left == other.left; + } else if (!keyOrAddress.is_left && !other.is_left) { + return keyOrAddress.right == other.right; + } else { + return false; + } + } } diff --git a/contracts/utils/src/test/UtilsSimulator.ts b/contracts/utils/src/test/UtilsSimulator.ts index c55c802f..df5f9631 100644 --- a/contracts/utils/src/test/UtilsSimulator.ts +++ b/contracts/utils/src/test/UtilsSimulator.ts @@ -22,8 +22,7 @@ import { UtilsPrivateState, UtilsWitnesses } from '../witnesses'; * @template L - The ledger type, fixed to Contract.Ledger. */ export class UtilsContractSimulator - implements IContractSimulator -{ + implements IContractSimulator { /** @description The underlying contract instance managing contract logic. */ readonly contract: MockUtils; @@ -91,4 +90,20 @@ export class UtilsContractSimulator public isKeyOrAddressZero(keyOrAddress: Either): boolean { return this.contract.circuits.isKeyOrAddressZero(this.circuitContext, keyOrAddress).result; } + + /** + * @description Returns whether `keyOrAddress` is equal to `other`. Assumes that a ZswapCoinPublicKey + * and a ContractAddress can never be equal + * + * @public + * @param {Either} keyOrAddress The target value to check + * @param {Either} other The other value to check + * @returns {boolean} Returns true if `keyOrAddress` is is equal to `other`. + */ + public isKeyOrAddressEqual( + keyOrAddress: Either, + other: Either + ): boolean { + return this.contract.circuits.isKeyOrAddressEqual(this.circuitContext, keyOrAddress, other).result; + } } From 12fcb116016d62dedda39df890756e69c7e26223 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Fri, 25 Apr 2025 16:31:43 -0400 Subject: [PATCH 066/282] Adds tests for isKeyOrAddressEqual --- contracts/utils/src/test/utils.test.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index a24fc902..5bc3cdf3 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -2,7 +2,9 @@ import { UtilsContractSimulator } from './UtilsSimulator'; import * as contractUtils from './utils'; const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); +const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); const SOME_CONTRACT = contractUtils.createEitherTestContractAddress('SOME_CONTRACT'); +const OTHER_CONTRACT = contractUtils.createEitherTestContractAddress('OTHER_CONTRACT'); let contract: UtilsContractSimulator; @@ -20,4 +22,26 @@ describe('Utils', () => { expect(contract.isKeyOrAddressZero(SOME_CONTRACT)).toBeFalsy; }); }); + + describe('isKeyOrAddressEqual', () => { + it('should return true for two matching pubkeys', () => { + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_SOME_KEY)).toBeTruthy(); + }); + + it('should return true for two matching contract addresses', () => { + expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, SOME_CONTRACT)).toBeTruthy(); + }); + + it('should return false for two different pubkeys', () => { + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_OTHER_KEY)).toBeFalsy(); + }); + + it('should return false for two different contract addresses', () => { + expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, OTHER_CONTRACT)).toBeFalsy(); + }); + + it('should return false for two different address types', () => { + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, SOME_CONTRACT)).toBeFalsy(); + }); + }); }); From 7a5ad93249eeece94a2def31b491bb9344017df5 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Fri, 25 Apr 2025 17:56:06 -0400 Subject: [PATCH 067/282] Update witness function signature --- contracts/erc721/src/ERC721.compact | 13 +++++++--- .../erc721/src/witnesses/ERC721Witnesses.ts | 24 ++++++++++++++++--- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 03b88d9d..f8a4fa2d 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -29,8 +29,15 @@ module ERC721 { export ledger _operatorApprovals: Map, Map, Boolean>>; /// Private state - witness computeTokenURI(baseURI: Opaque<"string">): Opaque<"string">; - export witness baseURI(): Opaque<"string">; + /** + * @description Computes a tokenURI given a `baseURI` and `tokenId` + * + * @param baseURI - baseURI of the final tokenURI, defaults to the empty string + * @param tokenId - The token identifier + * + * @return {Opaque<"string">} - The final URI of the provided token identifier + */ + witness computeTokenURI(baseURI: Opaque<"string">, tokenId: Field): Opaque<"string">; /** * @description Initializes the contract by setting the name and symbol. @@ -97,7 +104,7 @@ module ERC721 { _requireOwned(tokenId); const baseURI = _baseURI(); - return disclose(computeTokenURI(baseURI)); + return disclose(computeTokenURI(baseURI, tokenId)); } export circuit _baseURI(): Opaque<"string"> { diff --git a/contracts/erc721/src/witnesses/ERC721Witnesses.ts b/contracts/erc721/src/witnesses/ERC721Witnesses.ts index 983ff01e..e6747b1c 100644 --- a/contracts/erc721/src/witnesses/ERC721Witnesses.ts +++ b/contracts/erc721/src/witnesses/ERC721Witnesses.ts @@ -1,3 +1,21 @@ -// This is how we type an empty object. -export type ERC721PrivateState = Record; -export const ERC721Witnesses = {}; +import * as Contract from "../artifacts/MockERC721/contract/index.cjs"; +import { WitnessContext } from "@midnight-ntwrk/compact-runtime"; + +export type ERC721PrivateState = { + tokenURI: string +}; + +export const ERC721Witnesses = { + /** + * @description A mock implementation of the computeTokenURI witness function + * + * @dev This function should be modified to meet the needs of your application + * + * @param {ERC721PrivateState} privateState The private state of the contract + * @param {string} baseURI The baseURI which is the empty string by default + * @returns {[ERC721PrivateState, string]} A tuple of the new private state and the declared return value + */ + computeTokenURI({ privateState }: WitnessContext, baseURI: string, tokenId: bigint): [ERC721PrivateState, string] { + return [privateState, baseURI + privateState.tokenURI + tokenId.toString()]; + } +} From 882d54d383b992b0b8854b025de15ad1ae877b2a Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Fri, 25 Apr 2025 18:56:42 -0400 Subject: [PATCH 068/282] write boilerplate fns for testing, function impl consistency, add missing fn to mock --- contracts/erc721/src/ERC721.compact | 8 +- .../erc721/src/test/mocks/MockERC721.compact | 4 + .../src/test/simulators/ERC721Simulator.ts | 95 ++++++++++++++++++- 3 files changed, 104 insertions(+), 3 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index f8a4fa2d..da381fdc 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -115,10 +115,12 @@ module ERC721 { to: Either, tokenId: Field ): [] { + // TMP - Waiting for contract-to-contract calls to handle `right` with contract address + const auth = left(own_public_key()); _approve( to, tokenId, - left(own_public_key()) + auth ); } @@ -132,8 +134,10 @@ module ERC721 { operator: Either, approved: Boolean ): [] { + // TMP - Waiting for contract-to-contract calls to handle `right` with contract address + const owner = left(own_public_key()); _setApprovalForAll( - left(own_public_key()), + owner, operator, approved ); diff --git a/contracts/erc721/src/test/mocks/MockERC721.compact b/contracts/erc721/src/test/mocks/MockERC721.compact index 77592a13..40b92c01 100644 --- a/contracts/erc721/src/test/mocks/MockERC721.compact +++ b/contracts/erc721/src/test/mocks/MockERC721.compact @@ -180,4 +180,8 @@ export circuit _transfer( tokenId: Field ): [] { return ERC721__transfer(from, to, tokenId); +} + +export circuit _baseURI(): Opaque<"string"> { + return ERC721__baseURI(); } \ No newline at end of file diff --git a/contracts/erc721/src/test/simulators/ERC721Simulator.ts b/contracts/erc721/src/test/simulators/ERC721Simulator.ts index 6e7fc37e..8660d422 100644 --- a/contracts/erc721/src/test/simulators/ERC721Simulator.ts +++ b/contracts/erc721/src/test/simulators/ERC721Simulator.ts @@ -14,6 +14,7 @@ import { Either, ZswapCoinPublicKey, ContractAddress, + pureCircuits } from '../../artifacts/MockERC721/contract/index.cjs'; // Combined imports import { MaybeString } from '../types'; import type { IContractSimulator } from '../types'; @@ -47,7 +48,7 @@ export class ERC721Simulator currentContractState, currentZswapLocalState, } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)), name, symbol, + constructorContext({ tokenURI: "https://www.mynft.test/" }, '0'.repeat(64)), name, symbol, ); this.circuitContext = { currentPrivateState, @@ -118,5 +119,97 @@ export class ERC721Simulator public ownerOf(tokenId: bigint): Either { return this.contract.impureCircuits.ownerOf(this.circuitContext, tokenId).result; } + + public tokenURI(tokenId: bigint): string { + return this.contract.impureCircuits.tokenURI(this.circuitContext, tokenId).result; + } + + public _baseURI(): string { + return pureCircuits._baseURI(); + } + + public approve(to: Either, tokenId: bigint): [] { + return this.contract.impureCircuits.approve(this.circuitContext, to, tokenId).result; + } + + public getApproved(tokenId: bigint): Either { + return this.contract.impureCircuits.getApproved(this.circuitContext, tokenId).result; + } + + public setApprovalForAll(operator: Either, approved: boolean): [] { + return this.contract.impureCircuits.setApprovalForAll(this.circuitContext, operator, approved).result; + } + + public isApprovedForAll(owner: Either, operator: Either): boolean { + return this.contract.impureCircuits.isApprovedForAll(this.circuitContext, owner, operator).result; + } + + public transferFrom(from: Either, to: Either, tokenId: bigint): [] { + return this.contract.impureCircuits.transferFrom(this.circuitContext, from, to, tokenId).result; + } + + public safeTransferFrom(from: Either, to: Either, tokenId: bigint): [] { + return this.contract.impureCircuits.safeTransferFrom(this.circuitContext, from, to, tokenId).result; + } + + public _safeTransferFromWith(from: Either, to: Either, tokenId: bigint, data: string): [] { + return this.contract.impureCircuits._safeTransferFrom(this.circuitContext, from, to, tokenId, data).result; + } + + public _requireOwned(tokenId: bigint): Either { + return this.contract.impureCircuits._requireOwned(this.circuitContext, tokenId).result; + } + + public _ownerOf(tokenId: bigint): Either { + return this.contract.impureCircuits._ownerOf(this.circuitContext, tokenId).result; + } + + public _update(to: Either, tokenId: bigint, auth: Either): Either { + return this.contract.impureCircuits._update(this.circuitContext, to, tokenId, auth).result; + } + + public _approve(to: Either, tokenId: bigint, auth: Either): [] { + return this.contract.impureCircuits._approve(this.circuitContext, to, tokenId, auth).result; + } + + public _checkAuthorized(owner: Either, spender: Either, tokenId: bigint): [] { + return this.contract.impureCircuits._checkAuthorized(this.circuitContext, owner, spender, tokenId).result; + } + + public _isAuthorized(owner: Either, spender: Either, tokenId: bigint): boolean { + return this.contract.impureCircuits._isAuthorized(this.circuitContext, owner, spender, tokenId).result; + } + + public _getApproved(tokenId: bigint): Either { + return this.contract.impureCircuits._getApproved(this.circuitContext, tokenId).result; + } + + public _setApprovalForAll(owner: Either, operator: Either, approved: boolean): [] { + return this.contract.impureCircuits._setApprovalForAll(this.circuitContext, owner, operator, approved).result; + } + + public _increaseBalance(account: Either, value: bigint): [] { + return this.contract.impureCircuits._increaseBalance(this.circuitContext, account, value).result; + } + + public _mint(to: Either, tokenId: bigint): [] { + return this.contract.impureCircuits._mint(this.circuitContext, to, tokenId).result; + } + + public _safeMint(to: Either, tokenId: bigint): [] { + return this.contract.impureCircuits._safeMint(this.circuitContext, to, tokenId).result; + } + + public __safeMint(to: Either, tokenId: bigint, data: string): [] { + return this.contract.impureCircuits.__safeMint(this.circuitContext, to, tokenId, data).result; + } + + public _burn(tokenId: bigint): [] { + return this.contract.impureCircuits._burn(this.circuitContext, tokenId).result; + } + + public _transfer(from: Either, to: Either, tokenId: bigint): [] { + return this.contract.impureCircuits._transfer(this.circuitContext, from, to, tokenId).result; + } } From 5037cf78bc48f13ecd3cfefb3934f81e0d6dc991 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Thu, 10 Apr 2025 03:29:49 -0500 Subject: [PATCH 069/282] Add development section to readme (#21) * add development section to readme * add warning * fix fmt --- README.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 23edf257..90f64ec7 100644 --- a/README.md +++ b/README.md @@ -1 +1,31 @@ -# midnight-contracts +# OpenZeppelin Contracts for Midnight + +**A library for secure smart contract development** written in Compact for [Midnight](https://midnight.network/). + +> ## ⚠️ WARNING! ⚠️ +> +> This repo contains highly experimental code. +> Expect rapid iteration. +> **Use at your own risk.** + +## Development + +Clone the repository: + +```bash +git clone git@github.com:OpenZeppelin/midnight-contracts.git +``` + +`cd` into it and then install dependencies and build: + +```bash +cd midnight-contracts +yarn +npx turbo build +``` + +### Run tests + +```bash +npx turbo test +``` From fc79731bb3a2d1b85b24f8a26ccc90abb7c6b5ef Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 11 Apr 2025 09:58:09 -0500 Subject: [PATCH 070/282] tidy up code (#23) --- contracts/erc20/.eslintignore | 1 - contracts/erc20/.eslintrc.cjs | 30 -- contracts/erc20/jest.config.ts | 28 -- contracts/erc20/js-resolver.cjs | 16 - contracts/erc20/package.json | 32 -- contracts/erc20/src/test/erc20.test.ts | 471 ------------------ .../erc20/src/test/mocks/MockERC20.compact | 106 ---- .../src/test/simulators/ERC20Simulator.ts | 299 ----------- contracts/erc20/src/test/simulators/index.ts | 1 - contracts/erc20/src/test/types/index.ts | 6 - contracts/erc20/src/test/types/test.ts | 23 - contracts/erc20/src/test/utils/address.ts | 78 --- contracts/erc20/src/test/utils/index.ts | 2 - contracts/erc20/src/test/utils/test.ts | 67 --- .../erc20/src/witnesses/ERC20Witnesses.ts | 3 - contracts/erc20/src/witnesses/index.ts | 2 - contracts/erc20/tsconfig.build.json | 5 - contracts/erc20/tsconfig.json | 21 - 18 files changed, 1191 deletions(-) delete mode 100644 contracts/erc20/.eslintignore delete mode 100644 contracts/erc20/.eslintrc.cjs delete mode 100644 contracts/erc20/jest.config.ts delete mode 100644 contracts/erc20/js-resolver.cjs delete mode 100644 contracts/erc20/package.json delete mode 100644 contracts/erc20/src/test/erc20.test.ts delete mode 100644 contracts/erc20/src/test/mocks/MockERC20.compact delete mode 100644 contracts/erc20/src/test/simulators/ERC20Simulator.ts delete mode 100644 contracts/erc20/src/test/simulators/index.ts delete mode 100644 contracts/erc20/src/test/types/index.ts delete mode 100644 contracts/erc20/src/test/types/test.ts delete mode 100644 contracts/erc20/src/test/utils/address.ts delete mode 100644 contracts/erc20/src/test/utils/index.ts delete mode 100644 contracts/erc20/src/test/utils/test.ts delete mode 100644 contracts/erc20/src/witnesses/ERC20Witnesses.ts delete mode 100644 contracts/erc20/src/witnesses/index.ts delete mode 100644 contracts/erc20/tsconfig.build.json delete mode 100644 contracts/erc20/tsconfig.json diff --git a/contracts/erc20/.eslintignore b/contracts/erc20/.eslintignore deleted file mode 100644 index 327555cd..00000000 --- a/contracts/erc20/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -src/artifacts diff --git a/contracts/erc20/.eslintrc.cjs b/contracts/erc20/.eslintrc.cjs deleted file mode 100644 index 581f1d49..00000000 --- a/contracts/erc20/.eslintrc.cjs +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - node: true, - jest: true, - }, - extends: [ - 'standard-with-typescript', - 'plugin:prettier/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - overrides: [], - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['tsconfig.json'], - }, - rules: { - '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 - '@typescript-eslint/no-floating-promises': 'warn', - '@typescript-eslint/promise-function-async': 'off', - '@typescript-eslint/no-redeclare': 'off', - '@typescript-eslint/no-invalid-void-type': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/consistent-type-definitions': 'off' - }, -}; diff --git a/contracts/erc20/jest.config.ts b/contracts/erc20/jest.config.ts deleted file mode 100644 index 3cbccc1b..00000000 --- a/contracts/erc20/jest.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Config } from "@jest/types"; - -const config: Config.InitialOptions = { - preset: "ts-jest/presets/default-esm", - testEnvironment: "node", - verbose: true, - roots: [""], - modulePaths: [""], - passWithNoTests: false, - testMatch: ["**/*.test.ts"], - extensionsToTreatAsEsm: [".ts"], - collectCoverage: true, - resolver: '/js-resolver.cjs', - coverageThreshold: { - global: { - branches: 50, - functions: 50, - lines: 50, - }, - }, - reporters: [ - "default", - ["jest-junit", { outputDirectory: "reports", outputName: "report.xml" }], - ["jest-html-reporters", { publicPath: "reports", filename: "report.html" }], - ], -}; - -export default config; diff --git a/contracts/erc20/js-resolver.cjs b/contracts/erc20/js-resolver.cjs deleted file mode 100644 index cc9ed285..00000000 --- a/contracts/erc20/js-resolver.cjs +++ /dev/null @@ -1,16 +0,0 @@ -const jsResolver = (path, options) => { - const jsExtRegex = /\.js$/i - const resolver = options.defaultResolver - if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { - const newPath = path.replace(jsExtRegex, '.ts'); - try { - return resolver(newPath, options) - } catch { - // use default resolver - } - } - - return resolver(path, options) -} - -module.exports = jsResolver diff --git a/contracts/erc20/package.json b/contracts/erc20/package.json deleted file mode 100644 index d914daf0..00000000 --- a/contracts/erc20/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "@openzeppelin-midnight-contracts/erc20-contract", - "type": "module", - "main": "dist/index.js", - "module": "dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "require": "./dist/index.js", - "import": "./dist/index.js", - "default": "./dist/index.js" - } - }, - "scripts": { - "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", - "test": "NODE_OPTIONS=--experimental-vm-modules jest", - "prepack": "yarn build", - "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/ERC20.compact ./dist", - "lint": "eslint src", - "typecheck": "tsc -p tsconfig.json --noEmit" - }, - "dependencies": { - "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" - }, - "devDependencies": { - "@midnight-ntwrk/compact": "workspace:*", - "eslint": "^8.52.0", - "jest": "^29.7.0", - "typescript": "^5.2.2" - } -} diff --git a/contracts/erc20/src/test/erc20.test.ts b/contracts/erc20/src/test/erc20.test.ts deleted file mode 100644 index 939f1c2b..00000000 --- a/contracts/erc20/src/test/erc20.test.ts +++ /dev/null @@ -1,471 +0,0 @@ -import { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; -import { ERC20Simulator } from './simulators'; -import { MaybeString } from './types'; -import * as utils from './utils'; - -const NO_STRING: MaybeString = { - is_some: false, - value: '' -}; -const NAME: MaybeString = { - is_some: true, - value: "NAME" -}; -const SYMBOL: MaybeString = { - is_some: true, - value: "SYMBOL" -}; -const DECIMALS: bigint = 18n; - -const AMOUNT: bigint = BigInt(250); -const MAX_UINT128 = BigInt(2**128) - BigInt(1); - -const OWNER = String(Buffer.from("OWNER", 'ascii').toString('hex')).padStart(64, '0'); -const SPENDER = String(Buffer.from("SPENDER", 'ascii').toString('hex')).padStart(64, '0'); -const UNAUTHORIZED = String(Buffer.from("UNAUTHORIZED", 'ascii').toString('hex')).padStart(64, '0'); -const ZERO = String().padStart(64, '0'); -const Z_OWNER = utils.createEitherTestUser('OWNER'); -const Z_RECIPIENT = utils.createEitherTestUser('RECIPIENT'); -const Z_SPENDER = utils.createEitherTestUser('SPENDER'); -const Z_OTHER = utils.createEitherTestUser('OTHER'); -const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); - -let token: ERC20Simulator; -let caller: CoinPublicKey; - -describe('ERC20', () => { - describe('initializer and metadata', () => { - it('should initialize metadata', () => { - token = new ERC20Simulator(NAME, SYMBOL, DECIMALS); - - expect(token.name()).toEqual(NAME); - expect(token.symbol()).toEqual(SYMBOL); - expect(token.decimals()).toEqual(DECIMALS); - }); - - it('should initialize empty metadata', () => { - const NO_DECIMALS = 0n; - token = new ERC20Simulator(NO_STRING, NO_STRING, NO_DECIMALS); - - expect(token.name()).toEqual(NO_STRING); - expect(token.symbol()).toEqual(NO_STRING); - expect(token.decimals()).toEqual(NO_DECIMALS); - }); - }); - - beforeEach(() => { - token = new ERC20Simulator(NAME, SYMBOL, DECIMALS); - }); - - describe('totalSupply', () => { - it('returns 0 when there is no supply', () => { - expect(token.totalSupply()).toEqual(0n); - }); - - it('returns the amount of existing tokens when there is a supply', () => { - token._mint(Z_OWNER, AMOUNT); - expect(token.totalSupply()).toEqual(AMOUNT); - }) - }) - - describe('balanceOf', () => { - it('should return zero when requested account has no balance', () => { - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - - it('should return balance when requested account has tokens', () => { - token._mint(Z_OWNER, AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); - }); - - describe('transfer', () => { - beforeEach(() => { - token._mint(Z_OWNER, AMOUNT); - - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); - }); - - afterEach(() => { - expect(token.totalSupply()).toEqual(AMOUNT); - }); - - it('should transfer partial', () => { - const partialAmt = AMOUNT - 1n; - caller = OWNER; - const txSuccess = token.transfer(Z_RECIPIENT, partialAmt, caller); - - expect(txSuccess).toBeTruthy(); - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); - }); - - it('should transfer full', () => { - caller = OWNER; - const txSuccess = token.transfer(Z_RECIPIENT, AMOUNT, caller); - - expect(txSuccess).toBeTruthy(); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); - }); - - it('should fail with insufficient balance', () => { - caller = OWNER; - - expect(() => { - token.transfer(Z_RECIPIENT, AMOUNT + 1n, caller); - }).toThrow('ERC20: insufficient balance'); - }); - - it('should fail with transfer from zero', () => { - caller = ZERO; - - expect(() => { - token.transfer(Z_RECIPIENT, AMOUNT, caller); - }).toThrow('ERC20: invalid sender'); - }); - - it('should fail with transfer to zero', () => { - caller = OWNER; - - expect(() => { - token.transfer(utils.ZERO_ADDRESS, AMOUNT, caller); - }).toThrow('ERC20: invalid receiver'); - }); - - it('should allow transfer of 0 tokens', () => { - const txSuccess = token.transfer(Z_RECIPIENT, 0n, caller); - - expect(txSuccess).toBeTruthy(); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); - }); - - it('should handle transfer with empty _balances', () => { - caller = SPENDER; - - expect(() => { - token.transfer(Z_RECIPIENT, 1n, caller); - }).toThrow('ERC20: insufficient balance'); - }); - }); - - describe('approve', () => { - beforeEach(() => { - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - }); - - it('should approve and update allowance', () => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); - }); - - it('should approve and update allowance for multiple spenders', () => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); - - token.approve(Z_OTHER, AMOUNT, caller); - expect(token.allowance(Z_OWNER, Z_OTHER)).toEqual(AMOUNT); - - expect(token.allowance(Z_OWNER, Z_RECIPIENT)).toEqual(0n); - }); - - it('should fail when approve from zero', () => { - caller = ZERO; - - expect(() => { - token.approve(Z_SPENDER, AMOUNT, caller); - }).toThrow('ERC20: invalid owner'); - }); - - it('should fail when approve to zero', () => { - caller = OWNER; - - expect(() => { - token.approve(utils.ZERO_ADDRESS, AMOUNT, caller); - }).toThrow('ERC20: invalid spender'); - }); - - it('should transfer exact allowance and fail subsequent transfer', () => { - token._mint(Z_OWNER, AMOUNT); - caller = OWNER; - token.approve(Z_SPENDER, AMOUNT, caller); - - caller = SPENDER; - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, 1n, caller); - }).toThrow('ERC20: insufficient allowance'); - }); - - it('should allow approve of 0 tokens', () => { - caller = OWNER; - token.approve(Z_SPENDER, 0n, caller); - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - }); - - it('should handle allowance with empty _allowances', () => { - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - }); - }); - - describe('transferFrom', () => { - beforeEach(() => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); - token._mint(Z_OWNER, AMOUNT); - }); - - afterEach(() => { - expect(token.totalSupply()).toEqual(AMOUNT); - }); - - it('should transferFrom spender (partial)', () => { - caller = SPENDER; - const partialAmt = AMOUNT - 1n; - - const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, partialAmt, caller); - expect(txSuccess).toBeTruthy(); - - // Check balances - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); - // Check leftover allowance - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(1n); - }); - - it('should transferFrom spender (full)', () => { - caller = SPENDER; - - const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - expect(txSuccess).toBeTruthy(); - - // Check balances - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); - // Check no allowance - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - }); - - it('should transferFrom and not consume infinite allowance', () => { - caller = OWNER; - token.approve(Z_SPENDER, MAX_UINT128, caller); - - caller = SPENDER; - const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - expect(txSuccess).toBeTruthy(); - - // Check balances - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); - // Check infinite allowance - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(MAX_UINT128); - }); - - it ('should fail when transfer amount exceeds allowance', () => { - caller = SPENDER; - - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n); - }).toThrow('ERC20: insufficient allowance'); - }); - - it ('should fail when transfer amount exceeds balance', () => { - caller = OWNER; - // Increase allowance > balance - token.approve(Z_SPENDER, AMOUNT + 1n, caller); - - caller = SPENDER; - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n, caller); - }).toThrow('ERC20: insufficient balance'); - }); - - it('should fail when spender does not have allowance', () => { - caller = UNAUTHORIZED; - - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - }).toThrow("ERC20: insufficient allowance"); - }); - - it('should fail to transferFrom zero address', () => { - caller = ZERO; - - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - }).toThrow("ERC20: insufficient allowance"); - }); - - it('should fail to transferFrom to the zero address', () => { - caller = SPENDER; - - expect(() => { - token.transferFrom(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT, caller); - }).toThrow("ERC20: invalid receiver"); - }); - }); - - describe('_transfer', () => { - beforeEach(() => { - token._mint(Z_OWNER, AMOUNT); - }); - - afterEach(() => { - expect(token.totalSupply()).toEqual(AMOUNT); - }); - - it('should update balances (partial)', () => { - const partialAmt = AMOUNT - 1n; - token._transfer(Z_OWNER, Z_RECIPIENT, partialAmt); - - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); - }); - }) - - describe('_mint', () => { - it('should mint and update supply', () => { - expect(token.totalSupply()).toEqual(0n); - - token._mint(Z_RECIPIENT, AMOUNT); - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); - }); - - it('should catch mint overflow', () => { - token._mint(Z_RECIPIENT, MAX_UINT128); - - expect(() => { - token._mint(Z_RECIPIENT, 1n); - }).toThrow('ERC20: arithmetic overflow'); - }); - - it('should not mint to zero pubkey', () => { - expect(() => { - token._mint(utils.ZERO_KEY, AMOUNT); - }).toThrow('ERC20: invalid receiver'); - }); - - it('should not mint to zero contract address', () => { - expect(() => { - token._mint(utils.ZERO_ADDRESS, AMOUNT); - }).toThrow('ERC20: invalid receiver'); - }); - - it('should allow mint of 0 tokens', () => { - token._mint(Z_OWNER, 0n); - expect(token.totalSupply()).toEqual(0n); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - }); - - describe('_burn', () => { - beforeEach(() => { - token._mint(Z_OWNER, AMOUNT); - }); - - it('should burn tokens', () => { - token._burn(Z_OWNER, 1n); - - const afterBurn = AMOUNT - 1n; - expect(token.balanceOf(Z_OWNER)).toEqual(afterBurn); - expect(token.totalSupply()).toEqual(afterBurn); - }); - - it('should throw when burning from zero', () => { - expect(() => { - token._burn(utils.ZERO_KEY, AMOUNT); - }).toThrow('ERC20: invalid sender'); - }); - - it('should throw when burn amount is greater than balance', () => { - expect(() => { - token._burn(Z_OWNER, AMOUNT + 1n); - }).toThrow('ERC20: insufficient balance'); - }); - - it('should allow burn of 0 tokens', () => { - token._burn(Z_OWNER, 0n); - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); - }); - - describe('_update', () => { - it('should update from zero to non-zero (mint)', () => { - expect(token.totalSupply()).toEqual(0n); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - - token._update(utils.ZERO_KEY, Z_OWNER, AMOUNT); - - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); - - it('should catch overflow from zero to non-zero (mint)', () => { - token._update(utils.ZERO_KEY, Z_OWNER, MAX_UINT128); - - expect(() => { - token._update(utils.ZERO_KEY, Z_OWNER, 1n); - }).toThrow('ERC20: arithmetic overflow'); - }); - - describe('with minted tokens', () => { - beforeEach(() => { - token._update(utils.ZERO_ADDRESS, Z_OWNER, AMOUNT); - - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); - - it('should update from non-zero to zero (burn)', () => { - token._update(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); - - expect(token.totalSupply()).toEqual(0n); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - - it('should catch overflow from non-zero to zero (burn)', () => { - token._update(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); - - expect(() => { - token._update(Z_OWNER, utils.ZERO_ADDRESS, 1n); - }).toThrow('ERC20: insufficient balance'); - }); - - it('should update from non-zero to non-zero (transfer)', () => { - token._update(Z_OWNER, Z_RECIPIENT, AMOUNT - 1n); - - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); - }); - }); - }); - - describe('Multiple Operations', () => { - it('should handle mint → transfer → burn sequence', () => { - token._mint(Z_OWNER, AMOUNT); - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - - caller = OWNER; - token.transfer(Z_RECIPIENT, AMOUNT - 1n, caller); - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); - - token._burn(Z_OWNER, 1n); - expect(token.totalSupply()).toEqual(AMOUNT - 1n); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - }); -}); diff --git a/contracts/erc20/src/test/mocks/MockERC20.compact b/contracts/erc20/src/test/mocks/MockERC20.compact deleted file mode 100644 index e5e8a9da..00000000 --- a/contracts/erc20/src/test/mocks/MockERC20.compact +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.14.0; - -import CompactStandardLibrary; - -import "../../ERC20" prefix ERC20_; - -export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; - -constructor( - _name: Maybe>, - _symbol: Maybe>, - _decimals:Uint<8> -) { - ERC20_initializer(_name, _symbol, _decimals); -} - -export circuit name(): Maybe> { - return ERC20_name(); -} - -export circuit symbol(): Maybe> { - return ERC20_symbol(); -} - -export circuit decimals(): Uint<8> { - return ERC20_decimals(); -} - -export circuit totalSupply(): Uint<128> { - return ERC20_totalSupply(); -} - -export circuit balanceOf(account: Either): Uint<128> { - return ERC20_balanceOf(account); -} - -export circuit allowance( - owner: Either, - spender: Either -): Uint<128> { - return ERC20_allowance(owner, spender); -} - -export circuit transfer(to: Either, value: Uint<128>): Boolean { - return ERC20_transfer(to, value); -} - -export circuit transferFrom( - from: Either, - to: Either, - value: Uint<128> -): Boolean { - return ERC20_transferFrom(from, to, value); -} - -export circuit approve(spender: Either, value: Uint<128>): Boolean { - return ERC20_approve(spender, value); -} - -export circuit _approve( - owner: Either, - spender: Either, - value: Uint<128> -): [] { - return ERC20__approve(owner, spender, value); -} - -export circuit _transfer( - from: Either, - to: Either, - value: Uint<128> -): [] { - return ERC20__transfer(from, to, value); -} - -export circuit _mint( - account: Either, - value: Uint<128> -): [] { - return ERC20__mint(account, value); -} - -export circuit _burn( - account: Either, - value: Uint<128> -): [] { - return ERC20__burn(account, value); -} - -export circuit _update( - from: Either, - to: Either, - value: Uint<128> -): [] { - return ERC20__update(from, to, value); -} - -export circuit _spendAllowance( - owner: Either, - spender: Either, - value: Uint<128> -): [] { - return ERC20__spendAllowance(owner, spender, value); -} diff --git a/contracts/erc20/src/test/simulators/ERC20Simulator.ts b/contracts/erc20/src/test/simulators/ERC20Simulator.ts deleted file mode 100644 index a8e324da..00000000 --- a/contracts/erc20/src/test/simulators/ERC20Simulator.ts +++ /dev/null @@ -1,299 +0,0 @@ -import { - type CircuitContext, - CoinPublicKey, - type ContractState, - QueryContext, - constructorContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; -import { - type Ledger, - Contract as MockERC20, - ledger, - Either, - ZswapCoinPublicKey, - ContractAddress, -} from '../../artifacts/MockERC20/contract/index.cjs'; // Combined imports -import { MaybeString } from '../types'; -import type { IContractSimulator } from './../types'; -import { ERC20PrivateState, ERC20Witnesses } from '../../witnesses'; - -/** - * @description A simulator implementation of an erc20 contract for testing purposes. - * @template P - The private state type, fixed to ERC20PrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. - */ -export class ERC20Simulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockERC20; - - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor(name: MaybeString, symbol: MaybeString, decimals: bigint) { - this.contract = new MockERC20( - ERC20Witnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)), name, symbol, decimals, - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type ERC20PrivateState. - */ - public getCurrentPrivateState(): ERC20PrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; - } - - /** - * @description Returns the token name. - * @returns The token name. - */ - public name(): MaybeString { - return this.contract.impureCircuits.name(this.circuitContext).result; - } - - /** - * @description Returns the symbol of the token. - * @returns The token name. - */ - public symbol(): MaybeString { - return this.contract.impureCircuits.symbol(this.circuitContext).result; - } - - /** - * @description Returns the number of decimals used to get its user representation. - * @returns The account's token balance. - */ - public decimals(): bigint { - return this.contract.impureCircuits.decimals(this.circuitContext).result; - } - - /** - * @description Returns the value of tokens in existence. - * @returns The total supply of tokens. - */ - public totalSupply(): bigint { - return this.contract.impureCircuits.totalSupply(this.circuitContext).result; - } - - /** - * @description Returns the value of tokens owned by `account`. - * @param account The public key or contract address to query. - * @returns The account's token balance. - */ - public balanceOf(account: Either): bigint { - return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; - } - - /** - * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` - * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. - * @param owner The public key or contract address of approver. - * @param spender The public key or contract address of spender. - * @returns The `spender`'s allowance over `owner`'s tokens. - */ - public allowance( - owner: Either, - spender: Either - ): bigint { - return this.contract.impureCircuits.allowance(this.circuitContext, owner, spender).result; - } - - /** - * @description Moves a `value` amount of tokens from the caller's account to `to`. - * @param to The recipient of the transfer, either a user or a contract. - * @param value The amount to transfer. - * @param sender The simulated caller. - * @returns As per the IERC20 spec, this MUST return true. - */ - public transfer(to: Either, value: bigint, sender?: CoinPublicKey): boolean { - const res = this.contract.impureCircuits.transfer({ - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, to, value - ); - - this.circuitContext = res.context; - return res.result; - } - - /** - * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. - * `value` is the deducted from the caller's allowance. - * @param from The current owner of the tokens for the transfer, either a user or a contract. - * @param to The recipient of the transfer, either a user or a contract. - * @param value The amount to transfer. - * @param sender The simulated caller. - * @returns As per the IERC20 spec, this MUST return true. - */ - public transferFrom( - from: Either, - to: Either, - value: bigint, - sender?: CoinPublicKey - ): boolean { - const res = this.contract.impureCircuits.transferFrom({ - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, to, value - ); - - this.circuitContext = res.context; - return res.result; - } - - /** - * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. - * @param spender The Zswap key or ContractAddress that may spend on behalf of the caller. - * @param value The amount of tokens the `spender` may spend. - * @param sender The simulated caller. - * @returns Returns a boolean value indicating whether the operation succeeded. - */ - public approve(spender: Either, value: bigint, sender?: CoinPublicKey): boolean { - const res = this.contract.impureCircuits.approve({ - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - spender, value - ); - - this.circuitContext = res.context; - return res.result; - } - - /// - /// Internal - /// - - /** - * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. - * This internal function is equivalent to `approve`, and can be used to - * e.g. set automatic allowances for certain subsystems, etc. - * @param owner The owner of the tokens. - * @param spender The spender of the tokens. - * @param value The amount of tokens `spender` may spend on behalf of `owner`. - * @returns None. - */ - public _approve( - owner: Either, - spender: Either, - value: bigint - ) { - this.circuitContext = this.contract.impureCircuits._approve(this.circuitContext, owner, spender, value).context; - } - - /** - * @description Moves a `value` amount of tokens from `from` to `to`. - * This internal function is equivalent to {transfer}, and can be used to - * e.g. implement automatic token fees, slashing mechanisms, etc. - * @param from The owner of the tokens to transfer. - * @param to The receipient of the transferred tokens. - * @param value The amount of tokens to transfer. - */ - public _transfer( - from: Either, - to: Either, - value: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._transfer(this.circuitContext, from, to, value).context; - } - - /** - * @description Creates a `value` amount of tokens and assigns them to `account`, - * by transferring it from the zero address. Relies on the `update` mechanism. - * @param account The recipient of tokens minted. - * @param value The amount of tokens minted. - */ - public _mint(account: Either, value: bigint) { - this.circuitContext = this.contract.impureCircuits._mint(this.circuitContext, account, value).context; - } - - /** - * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. - * Relies on the `_update` mechanism. - * @param account The target owner of tokens to burn. - * @param value The amount of tokens to burn. - */ - public _burn(account: Either, value: bigint) { - this.circuitContext = this.contract.impureCircuits._burn(this.circuitContext, account, value).context; - } - - /** - * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` - * (or `to`) is the zero address. - * @param from The original owner of the tokens moved (which is 0 if tokens are minted). - * @param to The recipient of the tokens moved (which is 0 if tokens are burned). - * @param value The amount of tokens moved from `from` to `to`. - */ - public _update( - from: Either, - to: Either, - value: bigint - ) { - this.circuitContext = this.contract.impureCircuits._update(this.circuitContext, from, to, value).context; - } - - /** - * @description Updates `owner`'s allowance for `spender` based on spent `value`. - * Does not update the allowance value in case of infinite allowance. - * @param owner The owner of the tokens. - * @param spender The spender of the tokens. - * @param value The amount of token allowance to spend. - */ - public _spendAllowance( - owner: Either, - spender: Either, - value: bigint - ) { - this.circuitContext = this.contract.impureCircuits._spendAllowance(this.circuitContext, owner, spender, value).context; - } -} diff --git a/contracts/erc20/src/test/simulators/index.ts b/contracts/erc20/src/test/simulators/index.ts deleted file mode 100644 index 134f9c95..00000000 --- a/contracts/erc20/src/test/simulators/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { ERC20Simulator } from './ERC20Simulator'; diff --git a/contracts/erc20/src/test/types/index.ts b/contracts/erc20/src/test/types/index.ts deleted file mode 100644 index dac4e694..00000000 --- a/contracts/erc20/src/test/types/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type { IContractSimulator } from './test'; - -export type MaybeString = { - is_some: boolean, - value: string -} diff --git a/contracts/erc20/src/test/types/test.ts b/contracts/erc20/src/test/types/test.ts deleted file mode 100644 index 10fb6c98..00000000 --- a/contracts/erc20/src/test/types/test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; - -/** - * Generic interface for mock contract implementations. - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - */ -export interface IContractSimulator { - /** The contract's deployed address. */ - readonly contractAddress: string; - - /** The current circuit context. */ - circuitContext: CircuitContext

; - - /** Retrieves the current ledger state. */ - getCurrentPublicState(): L; - - /** Retrieves the current private state. */ - getCurrentPrivateState(): P; - - /** Retrieves the current contract state. */ - getCurrentContractState(): ContractState; -} diff --git a/contracts/erc20/src/test/utils/address.ts b/contracts/erc20/src/test/utils/address.ts deleted file mode 100644 index ef9a2842..00000000 --- a/contracts/erc20/src/test/utils/address.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import * as Compact from '../../artifacts/MockERC20/contract/index.cjs'; -import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; - -const PREFIX_ADDRESS = "0200"; - -export const pad = (s: string, n: number): Uint8Array => { - const encoder = new TextEncoder(); - const utf8Bytes = encoder.encode(s); - if (n < utf8Bytes.length) { - throw new Error(`The padded length n must be at least ${utf8Bytes.length}`); - } - const paddedArray = new Uint8Array(n); - paddedArray.set(utf8Bytes); - return paddedArray; -} - -/** - * @description Generates ZswapCoinPublicKey from `str` for testing purposes. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; -} - -/** - * @description Generates ContractAddress from `str` for testing purposes. - * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToAddress = (str: string): Compact.ContractAddress => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); - return { bytes: encodeContractAddress(fullAddress) }; -} - -/** - * @description Generates an Either object for ZswapCoinPublicKey for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ZswapCoinPublicKey. - */ -export const createEitherTestUser = (str: string) => { - return { - is_left: true, - left: encodeToPK(str), - right: encodeToAddress('') - } -} - -/** - * @description Generates an Either object for ContractAddress for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ContractAddress. - */ -export const createEitherTestContractAddress = (str: string) => { - return { - is_left: false, - left: encodeToPK(''), - right: encodeToAddress(str) - } -} - -export const ZERO_KEY = { - is_left: true, - left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, - right: encodeToAddress('') -} - -export const ZERO_ADDRESS = { - is_left: false, - left: encodeToPK(''), - right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) } -} diff --git a/contracts/erc20/src/test/utils/index.ts b/contracts/erc20/src/test/utils/index.ts deleted file mode 100644 index 731fe1ec..00000000 --- a/contracts/erc20/src/test/utils/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { useCircuitContext as circuitContext } from './test'; -export * from './address'; diff --git a/contracts/erc20/src/test/utils/test.ts b/contracts/erc20/src/test/utils/test.ts deleted file mode 100644 index 940ed612..00000000 --- a/contracts/erc20/src/test/utils/test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - QueryContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types'; - -/** - * Constructs a `CircuitContext` from the given state and sender information. - * - * This is typically used at runtime to provide the necessary context - * for executing circuits, including contract state, private state, - * sender identity, and transaction data. - * - * @template P - The type of the contract's private state. - * @param privateState - The current private state of the contract. - * @param contractState - The full contract state, including public and private data. - * @param sender - The public key of the sender (used in the circuit). - * @param contractAddress - The address of the deployed contract. - * @returns A fully populated `CircuitContext` for circuit execution. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContext

( - privateState: P, - contractState: ContractState, - sender: CoinPublicKey, - contractAddress: ContractAddress, -): CircuitContext

{ - return { - originalState: contractState, - currentPrivateState: privateState, - transactionContext: new QueryContext(contractState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} - -/** - * Prepares a new `CircuitContext` using the given sender and contract. - * - * Useful for mocking or updating the circuit context with a custom sender. - * - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - * @template C - The specific type of the contract implementing `MockContract`. - * @param contract - The contract instance implementing `MockContract`. - * @param sender - The public key to set as the sender in the new circuit context. - * @returns A new `CircuitContext` with the sender and updated context values. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContextSender>( - contract: C, - sender: CoinPublicKey, -): CircuitContext

{ - const currentPrivateState = contract.getCurrentPrivateState(); - const originalState = contract.getCurrentContractState(); - const contractAddress = contract.contractAddress; - - return { - originalState, - currentPrivateState, - transactionContext: new QueryContext(originalState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} diff --git a/contracts/erc20/src/witnesses/ERC20Witnesses.ts b/contracts/erc20/src/witnesses/ERC20Witnesses.ts deleted file mode 100644 index ed372fb7..00000000 --- a/contracts/erc20/src/witnesses/ERC20Witnesses.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This is how we type an empty object. -export type ERC20PrivateState = Record; -export const ERC20Witnesses = {}; diff --git a/contracts/erc20/src/witnesses/index.ts b/contracts/erc20/src/witnesses/index.ts deleted file mode 100644 index dc29bf8e..00000000 --- a/contracts/erc20/src/witnesses/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../artifacts/erc20/contract/index.cjs'; -export * from './ERC20Witnesses.js'; diff --git a/contracts/erc20/tsconfig.build.json b/contracts/erc20/tsconfig.build.json deleted file mode 100644 index f1132509..00000000 --- a/contracts/erc20/tsconfig.build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["src/test/**/*.ts"], - "compilerOptions": {} -} diff --git a/contracts/erc20/tsconfig.json b/contracts/erc20/tsconfig.json deleted file mode 100644 index 3e90b0a9..00000000 --- a/contracts/erc20/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "include": ["src/**/*.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - "declaration": true, - "lib": ["ESNext"], - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "node", - "allowJs": true, - "forceConsistentCasingInFileNames": true, - "noImplicitAny": true, - "strict": true, - "isolatedModules": true, - "sourceMap": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "skipLibCheck": true - } -} From d11abf3905de199e2076e80635df20c2d9928ca3 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Sat, 26 Apr 2025 00:53:30 -0500 Subject: [PATCH 071/282] Add pausable (#22) * add pausable * update repo structure * move mock contracts to mocks dir * fix initializable tests * move mocks to test * add comments to pausable simulator * add return type to isPaused * add line * fix comment * simplify build script * improve simulator export * fix test file name * Rename pausable.test.ts to Pausable.test.ts * chore: initializable in pausable style (#34) * move initializable and pausable to utils/ * remove barrel files, fix tests * update initializable mock, sim, and tests --------- Co-authored-by: Iskander --- contracts/erc721/src/test/utils/test.ts | 2 +- contracts/initializable/.eslintignore | 1 - contracts/initializable/.eslintrc.cjs | 30 ----- contracts/initializable/jest.config.ts | 28 ----- contracts/initializable/js-resolver.cjs | 16 --- contracts/initializable/package.json | 29 ----- .../initializable/src/Initializable.compact | 33 ------ .../src/MockInitializable.compact | 14 --- .../src/test/initializable.test.ts | 32 ----- .../initializable/src/test/types/index.ts | 1 - .../initializable/src/test/types/test.ts | 23 ---- .../initializable/src/test/utils/index.ts | 1 - .../initializable/src/test/utils/test.ts | 67 ----------- .../initializable/src/witnesses/index.ts | 2 - contracts/initializable/tsconfig.build.json | 5 - contracts/initializable/tsconfig.json | 21 ---- contracts/utils/package.json | 2 +- contracts/utils/src/Initializable.compact | 42 +++++++ contracts/utils/src/Pausable.compact | 61 ++++++++++ .../utils/src/test/Initializable.test.ts | 59 +++++++++ contracts/utils/src/test/Pausable.test.ts | 77 ++++++++++++ .../src/test/mocks/MockInitializable.compact | 18 +++ .../utils/src/test/mocks/MockPausable.compact | 26 ++++ .../src/{ => test/mocks}/MockUtils.compact | 2 +- .../simulators}/InitializableSimulator.ts | 28 +++-- .../src/test/simulators/PausableSimulator.ts | 112 ++++++++++++++++++ .../test/{ => simulators}/UtilsSimulator.ts | 12 +- contracts/utils/src/test/types/index.ts | 1 - contracts/utils/src/test/utils.test.ts | 22 ++-- contracts/utils/src/test/utils/index.ts | 4 - contracts/utils/src/test/utils/test.ts | 2 +- .../src/witnesses/InitializableWitnesses.ts | 0 .../utils/src/witnesses/PausableWitnesses.ts | 3 + contracts/utils/src/witnesses/index.ts | 2 - package.json | 1 - yarn.lock | 12 -- 36 files changed, 442 insertions(+), 349 deletions(-) delete mode 100644 contracts/initializable/.eslintignore delete mode 100644 contracts/initializable/.eslintrc.cjs delete mode 100644 contracts/initializable/jest.config.ts delete mode 100644 contracts/initializable/js-resolver.cjs delete mode 100644 contracts/initializable/package.json delete mode 100644 contracts/initializable/src/Initializable.compact delete mode 100644 contracts/initializable/src/MockInitializable.compact delete mode 100644 contracts/initializable/src/test/initializable.test.ts delete mode 100644 contracts/initializable/src/test/types/index.ts delete mode 100644 contracts/initializable/src/test/types/test.ts delete mode 100644 contracts/initializable/src/test/utils/index.ts delete mode 100644 contracts/initializable/src/test/utils/test.ts delete mode 100644 contracts/initializable/src/witnesses/index.ts delete mode 100644 contracts/initializable/tsconfig.build.json delete mode 100644 contracts/initializable/tsconfig.json create mode 100644 contracts/utils/src/Initializable.compact create mode 100644 contracts/utils/src/Pausable.compact create mode 100644 contracts/utils/src/test/Initializable.test.ts create mode 100644 contracts/utils/src/test/Pausable.test.ts create mode 100644 contracts/utils/src/test/mocks/MockInitializable.compact create mode 100644 contracts/utils/src/test/mocks/MockPausable.compact rename contracts/utils/src/{ => test/mocks}/MockUtils.compact (93%) rename contracts/{initializable/src/test => utils/src/test/simulators}/InitializableSimulator.ts (75%) create mode 100644 contracts/utils/src/test/simulators/PausableSimulator.ts rename contracts/utils/src/test/{ => simulators}/UtilsSimulator.ts (88%) delete mode 100644 contracts/utils/src/test/types/index.ts delete mode 100644 contracts/utils/src/test/utils/index.ts rename contracts/{initializable => utils}/src/witnesses/InitializableWitnesses.ts (100%) create mode 100644 contracts/utils/src/witnesses/PausableWitnesses.ts delete mode 100644 contracts/utils/src/witnesses/index.ts diff --git a/contracts/erc721/src/test/utils/test.ts b/contracts/erc721/src/test/utils/test.ts index 940ed612..a8840104 100644 --- a/contracts/erc721/src/test/utils/test.ts +++ b/contracts/erc721/src/test/utils/test.ts @@ -6,7 +6,7 @@ import { QueryContext, emptyZswapLocalState, } from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types'; +import type { IContractSimulator } from '../types/test'; /** * Constructs a `CircuitContext` from the given state and sender information. diff --git a/contracts/initializable/.eslintignore b/contracts/initializable/.eslintignore deleted file mode 100644 index 327555cd..00000000 --- a/contracts/initializable/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -src/artifacts diff --git a/contracts/initializable/.eslintrc.cjs b/contracts/initializable/.eslintrc.cjs deleted file mode 100644 index 581f1d49..00000000 --- a/contracts/initializable/.eslintrc.cjs +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - node: true, - jest: true, - }, - extends: [ - 'standard-with-typescript', - 'plugin:prettier/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - overrides: [], - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['tsconfig.json'], - }, - rules: { - '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 - '@typescript-eslint/no-floating-promises': 'warn', - '@typescript-eslint/promise-function-async': 'off', - '@typescript-eslint/no-redeclare': 'off', - '@typescript-eslint/no-invalid-void-type': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/consistent-type-definitions': 'off' - }, -}; diff --git a/contracts/initializable/jest.config.ts b/contracts/initializable/jest.config.ts deleted file mode 100644 index 3cbccc1b..00000000 --- a/contracts/initializable/jest.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Config } from "@jest/types"; - -const config: Config.InitialOptions = { - preset: "ts-jest/presets/default-esm", - testEnvironment: "node", - verbose: true, - roots: [""], - modulePaths: [""], - passWithNoTests: false, - testMatch: ["**/*.test.ts"], - extensionsToTreatAsEsm: [".ts"], - collectCoverage: true, - resolver: '/js-resolver.cjs', - coverageThreshold: { - global: { - branches: 50, - functions: 50, - lines: 50, - }, - }, - reporters: [ - "default", - ["jest-junit", { outputDirectory: "reports", outputName: "report.xml" }], - ["jest-html-reporters", { publicPath: "reports", filename: "report.html" }], - ], -}; - -export default config; diff --git a/contracts/initializable/js-resolver.cjs b/contracts/initializable/js-resolver.cjs deleted file mode 100644 index cc9ed285..00000000 --- a/contracts/initializable/js-resolver.cjs +++ /dev/null @@ -1,16 +0,0 @@ -const jsResolver = (path, options) => { - const jsExtRegex = /\.js$/i - const resolver = options.defaultResolver - if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { - const newPath = path.replace(jsExtRegex, '.ts'); - try { - return resolver(newPath, options) - } catch { - // use default resolver - } - } - - return resolver(path, options) -} - -module.exports = jsResolver diff --git a/contracts/initializable/package.json b/contracts/initializable/package.json deleted file mode 100644 index a04f1d3a..00000000 --- a/contracts/initializable/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "@openzeppelin-midnight-contracts/initializable-contract", - "type": "module", - "main": "dist/index.js", - "module": "dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "require": "./dist/index.js", - "import": "./dist/index.js", - "default": "./dist/index.js" - } - }, - "scripts": { - "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", - "test": "NODE_OPTIONS=--experimental-vm-modules jest", - "prepack": "yarn build", - "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/Initializable.compact ./dist", - "lint": "eslint src", - "typecheck": "tsc -p tsconfig.json --noEmit" - }, - "devDependencies": { - "@midnight-ntwrk/compact": "workspace:*", - "eslint": "^8.52.0", - "jest": "^29.7.0", - "typescript": "^5.2.2" - } -} diff --git a/contracts/initializable/src/Initializable.compact b/contracts/initializable/src/Initializable.compact deleted file mode 100644 index 648f7670..00000000 --- a/contracts/initializable/src/Initializable.compact +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma language_version >= 0.14.0; - -/** - * @module Initializable - * @description Initializable provides a simple mechanism that mimics the functionality of a constructor. - */ -module Initializable{ - import CompactStandardLibrary; - - export enum STATE { uninitialized, initialized } - - export ledger state: STATE; - - /** - * @description Initializes the state thus ensuring the calling circuit can only be called once. - * - * @returns None. - */ - export circuit initialize(): [] { - assert state == STATE.uninitialized "Contract already initialized"; - state = STATE.initialized; - } - - /** - * @description Returns true if the state is initialized. - * - * @returns {Boolean} - whether the contract has been initialized. - */ - export circuit isInitialized(): Boolean { - return (state == STATE.initialized); - } -} diff --git a/contracts/initializable/src/MockInitializable.compact b/contracts/initializable/src/MockInitializable.compact deleted file mode 100644 index d670f6d9..00000000 --- a/contracts/initializable/src/MockInitializable.compact +++ /dev/null @@ -1,14 +0,0 @@ -pragma language_version >= 0.14.0; - -import CompactStandardLibrary; -import Initializable prefix Initializable_; - -export { Initializable_state, Initializable_STATE }; - -export circuit initialize(): [] { - return Initializable_initialize(); -} - -export circuit isInitialized(): Boolean { - return Initializable_isInitialized(); -} diff --git a/contracts/initializable/src/test/initializable.test.ts b/contracts/initializable/src/test/initializable.test.ts deleted file mode 100644 index 15ee059c..00000000 --- a/contracts/initializable/src/test/initializable.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { it, describe, expect } from '@jest/globals'; -import { InitializableSimulator } from './InitializableSimulator.js'; -import { Initializable_STATE as STATE } from '../artifacts/MockInitializable/contract/index.cjs'; - -const contract = new InitializableSimulator(); - -describe('Initializable', () => { - it('should generate the initial ledger state deterministically', () => { - const contract2 = new InitializableSimulator(); - expect(contract.getCurrentPublicState()).toEqual(contract2.getCurrentPublicState()); - }); - - describe('initialize', () => { - it('should not be initialized', () => { - expect(contract.isInitialized()).toEqual(false); - expect(contract.getCurrentPublicState().initializableState).toEqual(STATE.uninitialized); - }); - - it('should initialize', () => { - contract.initialize(); - expect(contract.isInitialized()).toEqual(true); - expect(contract.getCurrentPublicState().initializableState).toEqual(STATE.initialized); - }); - }); - - it('should fail when re-initialized', () => { - expect(() => { - contract.initialize(); - contract.initialize(); - }).toThrow('Contract already initialized'); - }); -}); diff --git a/contracts/initializable/src/test/types/index.ts b/contracts/initializable/src/test/types/index.ts deleted file mode 100644 index db642b5e..00000000 --- a/contracts/initializable/src/test/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { IContractSimulator } from './test'; diff --git a/contracts/initializable/src/test/types/test.ts b/contracts/initializable/src/test/types/test.ts deleted file mode 100644 index 10fb6c98..00000000 --- a/contracts/initializable/src/test/types/test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; - -/** - * Generic interface for mock contract implementations. - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - */ -export interface IContractSimulator { - /** The contract's deployed address. */ - readonly contractAddress: string; - - /** The current circuit context. */ - circuitContext: CircuitContext

; - - /** Retrieves the current ledger state. */ - getCurrentPublicState(): L; - - /** Retrieves the current private state. */ - getCurrentPrivateState(): P; - - /** Retrieves the current contract state. */ - getCurrentContractState(): ContractState; -} diff --git a/contracts/initializable/src/test/utils/index.ts b/contracts/initializable/src/test/utils/index.ts deleted file mode 100644 index 14e02ef2..00000000 --- a/contracts/initializable/src/test/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { useCircuitContext as circuitContext } from './test'; diff --git a/contracts/initializable/src/test/utils/test.ts b/contracts/initializable/src/test/utils/test.ts deleted file mode 100644 index 5a9e5837..00000000 --- a/contracts/initializable/src/test/utils/test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - QueryContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types'; - -/** - * Constructs a `CircuitContext` from the given state and sender information. - * - * This is typically used at runtime to provide the necessary context - * for executing circuits, including contract state, private state, - * sender identity, and transaction data. - * - * @template P - The type of the contract's private state. - * @param privateState - The current private state of the contract. - * @param contractState - The full contract state, including public and private data. - * @param sender - The public key of the sender (used in the circuit). - * @param contractAddress - The address of the deployed contract. - * @returns A fully populated `CircuitContext` for circuit execution. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContext

( - privateState: P, - contractState: ContractState, - sender: CoinPublicKey, - contractAddress: ContractAddress, -): CircuitContext

{ - return { - originalState: contractState, - currentPrivateState: privateState, - transactionContext: new QueryContext(contractState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} - -/** - * Prepares a new `CircuitContext` using the given sender and contract. - * - * Useful for mocking or updating the circuit context with a custom sender. - * - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - * @template C - The specific type of the contract implementing `MockContract`. - * @param contract - The contract instance implementing `MockContract`. - * @param sender - The public key to set as the sender in the new circuit context. - * @returns A new `CircuitContext` with the sender and updated context values. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContextSender>( - contract: C, - sender: CoinPublicKey, -): CircuitContext

{ - const currentPrivateState = contract.getCurrentPrivateState(); - const originalState = contract.getCurrentContractState(); - const contractAddress = contract.contractAddress; - - return { - originalState, - currentPrivateState, - transactionContext: new QueryContext(originalState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} diff --git a/contracts/initializable/src/witnesses/index.ts b/contracts/initializable/src/witnesses/index.ts deleted file mode 100644 index d27dd4c3..00000000 --- a/contracts/initializable/src/witnesses/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../artifacts/initializable/contract/index.cjs'; -export * from './InitializableWitnesses'; diff --git a/contracts/initializable/tsconfig.build.json b/contracts/initializable/tsconfig.build.json deleted file mode 100644 index f1132509..00000000 --- a/contracts/initializable/tsconfig.build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["src/test/**/*.ts"], - "compilerOptions": {} -} diff --git a/contracts/initializable/tsconfig.json b/contracts/initializable/tsconfig.json deleted file mode 100644 index 3e90b0a9..00000000 --- a/contracts/initializable/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "include": ["src/**/*.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - "declaration": true, - "lib": ["ESNext"], - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "node", - "allowJs": true, - "forceConsistentCasingInFileNames": true, - "noImplicitAny": true, - "strict": true, - "isolatedModules": true, - "sourceMap": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "skipLibCheck": true - } -} diff --git a/contracts/utils/package.json b/contracts/utils/package.json index d914daf0..82019c84 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -16,7 +16,7 @@ "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", "test": "NODE_OPTIONS=--experimental-vm-modules jest", "prepack": "yarn build", - "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/ERC20.compact ./dist", + "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/{Initializable,Pausable,Utils}.compact ./dist", "lint": "eslint src", "typecheck": "tsc -p tsconfig.json --noEmit" }, diff --git a/contracts/utils/src/Initializable.compact b/contracts/utils/src/Initializable.compact new file mode 100644 index 00000000..a31c9bcf --- /dev/null +++ b/contracts/utils/src/Initializable.compact @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma language_version >= 0.14.0; + +/** + * @module Initializable + * @description Initializable provides a simple mechanism that mimics the functionality of a constructor. + */ +module Initializable { + import CompactStandardLibrary; + + export ledger _isInitialized: Boolean; + + /** + * @description Initializes the state thus ensuring the calling circuit can only be called once. + * + * @returns None. + */ + export circuit initialize(): [] { + assertNotInitialized(); + _isInitialized = true; + } + + /** + * @description Asserts that the contract has been initialized, throwing an error if not. + * + * @returns None. + * @throws Will throw "Initializable: contract not initialized" if the contract is not initialized. + */ + export circuit assertInitialized(): [] { + assert _isInitialized "Initializable: contract not initialized"; + } + + /** + * @description Asserts that the contract has not been initialized, throwing an error if it has. + * + * @returns None. + * @throws Will throw "Initializable: Contract already initialized" if the contract is already initialized. + */ + export circuit assertNotInitialized(): [] { + assert !_isInitialized "Initializable: contract already initialized"; + } +} diff --git a/contracts/utils/src/Pausable.compact b/contracts/utils/src/Pausable.compact new file mode 100644 index 00000000..8e9eba5b --- /dev/null +++ b/contracts/utils/src/Pausable.compact @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +pragma language_version >= 0.14.0; + +/** + * @module Pausable + * @description Pausable allows the implementing contract to implement + * an emergency stop mechanism. Only circuits that call `assertPaused` + * or `assertNotPaused` will be affected by this mechanism. + */ +module Pausable { + import CompactStandardLibrary; + + export ledger _isPaused: Boolean; + + /** + * @description Returns true if the contract is paused, and false otherwise. + * + * @returns {Boolean} True if paused. + */ + export circuit isPaused(): Boolean { + return _isPaused; + } + + /** + * @description Makes a circuit only callable when the contract is paused. + * + * @returns None. + */ + export circuit assertPaused(): [] { + assert _isPaused "Pausable: not paused"; + } + + /** + * @description Makes a circuit only callable when the contract is not paused. + * + * @returns None. + */ + export circuit assertNotPaused(): [] { + assert !_isPaused "Pausable: paused"; + } + + /** + * @description Triggers a stopped state. + * + * @returns None. + */ + export circuit _pause(): [] { + assertNotPaused(); + _isPaused = true; + } + + /** + * @description Lifts the pause on the contract. + * + * @returns None. + */ + export circuit _unpause(): [] { + assertPaused(); + _isPaused = false; + } +} diff --git a/contracts/utils/src/test/Initializable.test.ts b/contracts/utils/src/test/Initializable.test.ts new file mode 100644 index 00000000..5a306087 --- /dev/null +++ b/contracts/utils/src/test/Initializable.test.ts @@ -0,0 +1,59 @@ +import { it, describe, expect } from '@jest/globals'; +import { InitializableSimulator } from './simulators/InitializableSimulator'; + +let initializable: InitializableSimulator; + +describe('Initializable', () => { + beforeEach(() => { + initializable = new InitializableSimulator(); + }); + + it('should generate the initial ledger state deterministically', () => { + const initializable2 = new InitializableSimulator(); + expect(initializable.getCurrentPublicState()).toEqual(initializable2.getCurrentPublicState()); + }); + + describe('initialize', () => { + it('should not be initialized', () => { + expect(initializable.getCurrentPublicState().initializable_IsInitialized).toEqual(false); + }); + + it('should initialize', () => { + initializable.initialize(); + expect(initializable.getCurrentPublicState().initializable_IsInitialized).toEqual(true); + }); + }); + + it('should fail when re-initialized', () => { + expect(() => { + initializable.initialize(); + initializable.initialize(); + }).toThrow('Initializable: contract already initialized'); + }); + + describe('assertInitialized', () => { + it('should fail when not initialized', () => { + expect(() => { + initializable.assertInitialized(); + }).toThrow('Initializable: contract not initialized'); + }); + + it('should not fail when initialized', () => { + initializable.initialize(); + initializable.assertInitialized(); + }); + }); + + describe('assertNotInitialized', () => { + it('should fail when initialized', () => { + initializable.initialize(); + expect(() => { + initializable.assertNotInitialized(); + }).toThrow('Initializable: contract already initialized'); + }); + + it('should not fail when not initialied', () => { + initializable.assertNotInitialized(); + }); + }); +}); diff --git a/contracts/utils/src/test/Pausable.test.ts b/contracts/utils/src/test/Pausable.test.ts new file mode 100644 index 00000000..fdbb2fac --- /dev/null +++ b/contracts/utils/src/test/Pausable.test.ts @@ -0,0 +1,77 @@ +import { it, describe, expect } from '@jest/globals'; +import { PausableSimulator } from './simulators/PausableSimulator'; + +let pausable: PausableSimulator; + +describe('Pausable', () => { + beforeEach(() => { + pausable = new PausableSimulator(); + }); + + describe('when not paused', () => { + it('should not be paused in initial state', () => { + expect(pausable.isPaused()).toBe(false); + }); + + it('should throw when calling assertPaused', () => { + expect(() => { + pausable.assertPaused(); + }).toThrow('Pausable: not paused'); + }); + + it('should not throw when calling assertNotPaused', () => { + pausable.assertNotPaused(); + }); + + it('should pause from unpaused state', () => { + pausable.pause(); + expect(pausable.isPaused()).toBe(true); + }); + + it('should throw when unpausing in an unpaused state', () => { + expect(() => { + pausable.unpause(); + }).toThrow('Pausable: not paused'); + }); + }); + + describe('when paused', () => { + beforeEach(() => { + pausable.pause(); + }); + + it('should not throw when calling assertPaused', () => { + pausable.assertPaused(); + }); + + it('should throw when calling assertNotPaused', () => { + expect(() => { + pausable.assertNotPaused(); + }).toThrow('Pausable: paused'); + }); + + it('should unpause from paused state', () => { + pausable.unpause(); + expect(pausable.isPaused()).toBe(false); + }); + + it('should throw when pausing in an paused state', () => { + expect(() => { + pausable.pause(); + }).toThrow('Pausable: paused'); + }); + }); + + describe('Multiple Operations', () => { + it('should handle pause → unpause → pause sequence', () => { + pausable.pause(); + expect(pausable.isPaused()).toBe(true); + + pausable.unpause(); + expect(pausable.isPaused()).toBe(false); + + pausable.pause(); + expect(pausable.isPaused()).toBe(true); + }); + }); +}); diff --git a/contracts/utils/src/test/mocks/MockInitializable.compact b/contracts/utils/src/test/mocks/MockInitializable.compact new file mode 100644 index 00000000..e8722a47 --- /dev/null +++ b/contracts/utils/src/test/mocks/MockInitializable.compact @@ -0,0 +1,18 @@ +pragma language_version >= 0.14.0; + +import CompactStandardLibrary; +import "../../Initializable" prefix Initializable_; + +export { Initializable__isInitialized }; + +export circuit initialize(): [] { + return Initializable_initialize(); +} + +export circuit assertInitialized(): [] { + return Initializable_assertInitialized(); +} + +export circuit assertNotInitialized(): [] { + return Initializable_assertNotInitialized(); +} diff --git a/contracts/utils/src/test/mocks/MockPausable.compact b/contracts/utils/src/test/mocks/MockPausable.compact new file mode 100644 index 00000000..a564fbe6 --- /dev/null +++ b/contracts/utils/src/test/mocks/MockPausable.compact @@ -0,0 +1,26 @@ +pragma language_version >= 0.14.0; + +import CompactStandardLibrary; +import "../../Pausable" prefix Pausable_; + +export { Pausable__isPaused }; + +export circuit isPaused(): Boolean { + return Pausable_isPaused(); +} + +export circuit assertNotPaused(): [] { + return Pausable_assertNotPaused(); +} + +export circuit assertPaused(): [] { + return Pausable_assertPaused(); +} + +export circuit pause(): [] { + return Pausable__pause(); +} + +export circuit unpause(): [] { + return Pausable__unpause(); +} diff --git a/contracts/utils/src/MockUtils.compact b/contracts/utils/src/test/mocks/MockUtils.compact similarity index 93% rename from contracts/utils/src/MockUtils.compact rename to contracts/utils/src/test/mocks/MockUtils.compact index 27e61500..2044da04 100644 --- a/contracts/utils/src/MockUtils.compact +++ b/contracts/utils/src/test/mocks/MockUtils.compact @@ -4,7 +4,7 @@ pragma language_version >= 0.14.0; import CompactStandardLibrary; -import Utils prefix Utils_; +import "../../Utils" prefix Utils_; export { ZswapCoinPublicKey, ContractAddress, Either }; diff --git a/contracts/initializable/src/test/InitializableSimulator.ts b/contracts/utils/src/test/simulators/InitializableSimulator.ts similarity index 75% rename from contracts/initializable/src/test/InitializableSimulator.ts rename to contracts/utils/src/test/simulators/InitializableSimulator.ts index 89402a19..67810eec 100644 --- a/contracts/initializable/src/test/InitializableSimulator.ts +++ b/contracts/utils/src/test/simulators/InitializableSimulator.ts @@ -1,7 +1,7 @@ import { type CircuitContext, type ContractState, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; -import { Contract as MockInitializable, type Ledger, ledger } from '../artifacts/MockInitializable/contract/index.cjs'; -import type { IContractSimulator } from './types'; -import { InitializablePrivateState, InitializableWitnesses } from '../witnesses'; +import { Contract as MockInitializable, type Ledger, ledger } from '../../artifacts/MockInitializable/contract/index.cjs'; +import type { IContractSimulator } from '../types/test'; +import { InitializablePrivateState, InitializableWitnesses } from '../../witnesses/InitializableWitnesses'; /** * @description A simulator implementation of an utils contract for testing purposes. @@ -70,7 +70,7 @@ export class InitializableSimulator return this.circuitContext.originalState; } - /** + /** * @description Initializes the state. * @returns None. */ @@ -78,11 +78,21 @@ export class InitializableSimulator this.circuitContext = this.contract.impureCircuits.initialize(this.circuitContext).context; } - /** - * @description Returns true if the state is initialized. - * @returns Whether the contract has been initialized. + /** + * @description Asserts that the contract has been initialized, throwing an error if not. + * @returns None. + * @throws Will throw "Initializable: contract not initialized" if the contract is not initialized. + */ + public assertInitialized() { + return this.contract.impureCircuits.assertInitialized(this.circuitContext).result; + } + + /** + * @description Asserts that the contract has not been initialized, throwing an error if it has. + * @returns None. + * @throws Will throw "Initializable: contract already initialized" if the contract is already initialized. */ - public isInitialized(): boolean { - return this.contract.impureCircuits.isInitialized(this.circuitContext).result; + public assertNotInitialized() { + return this.contract.impureCircuits.assertNotInitialized(this.circuitContext).result; } } diff --git a/contracts/utils/src/test/simulators/PausableSimulator.ts b/contracts/utils/src/test/simulators/PausableSimulator.ts new file mode 100644 index 00000000..719a1b61 --- /dev/null +++ b/contracts/utils/src/test/simulators/PausableSimulator.ts @@ -0,0 +1,112 @@ +import { type CircuitContext, type ContractState, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; +import { Contract as MockPausable, type Ledger, ledger } from '../../artifacts/MockPausable/contract/index.cjs'; +import type { IContractSimulator } from '../types/test'; +import { PausablePrivateState, PausableWitnesses } from '../../witnesses/PausableWitnesses'; + +/** + * @description A simulator implementation of an utils contract for testing purposes. + * @template P - The private state type, fixed to UtilsPrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class PausableSimulator + implements IContractSimulator +{ + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockPausable; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor() { + this.contract = new MockPausable( + PausableWitnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)) + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type UtilsPrivateState. + */ + public getCurrentPrivateState(): PausablePrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + + /** + * @description Returns true if the contract is paused, and false otherwise. + * @returns True if paused. + */ + public isPaused(): boolean { + return this.contract.impureCircuits.isPaused(this.circuitContext).result; + } + + /** + * @description Makes a circuit only callable when the contract is paused. + * @returns None. + */ + public assertPaused() { + this.circuitContext = this.contract.impureCircuits.assertPaused(this.circuitContext).context; + } + + /** + * @description Makes a circuit only callable when the contract is not paused. + * @returns None. + */ + public assertNotPaused() { + this.circuitContext = this.contract.impureCircuits.assertNotPaused(this.circuitContext).context; + } + + /** + * @description Triggers a stopped state. + * @returns None. + */ + public pause() { + this.circuitContext = this.contract.impureCircuits.pause(this.circuitContext).context; + } + + /** + * @description Lifts the pause on the contract. + * @returns None. + */ + public unpause() { + this.circuitContext = this.contract.impureCircuits.unpause(this.circuitContext).context; + } +} diff --git a/contracts/utils/src/test/UtilsSimulator.ts b/contracts/utils/src/test/simulators/UtilsSimulator.ts similarity index 88% rename from contracts/utils/src/test/UtilsSimulator.ts rename to contracts/utils/src/test/simulators/UtilsSimulator.ts index df5f9631..dfacc17e 100644 --- a/contracts/utils/src/test/UtilsSimulator.ts +++ b/contracts/utils/src/test/simulators/UtilsSimulator.ts @@ -12,17 +12,23 @@ import { Either, ZswapCoinPublicKey, ContractAddress, -} from '../artifacts/MockUtils/contract/index.cjs'; // Combined imports -import type { IContractSimulator } from './types'; -import { UtilsPrivateState, UtilsWitnesses } from '../witnesses'; +} from '../../artifacts/MockUtils/contract/index.cjs'; // Combined imports +import type { IContractSimulator } from '../types/test'; +import { UtilsPrivateState, UtilsWitnesses } from '../../witnesses/UtilsWitnesses'; /** * @description A simulator implementation of an utils contract for testing purposes. * @template P - The private state type, fixed to UtilsPrivateState. * @template L - The ledger type, fixed to Contract.Ledger. */ +<<<<<<< HEAD:contracts/utils/src/test/UtilsSimulator.ts export class UtilsContractSimulator implements IContractSimulator { +======= +export class UtilsSimulator + implements IContractSimulator +{ +>>>>>>> b6f5215 (Add pausable (#22)):contracts/utils/src/test/simulators/UtilsSimulator.ts /** @description The underlying contract instance managing contract logic. */ readonly contract: MockUtils; diff --git a/contracts/utils/src/test/types/index.ts b/contracts/utils/src/test/types/index.ts deleted file mode 100644 index db642b5e..00000000 --- a/contracts/utils/src/test/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { IContractSimulator } from './test'; diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 5bc3cdf3..6d1e0e4b 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -1,15 +1,15 @@ -import { UtilsContractSimulator } from './UtilsSimulator'; -import * as contractUtils from './utils'; +import { UtilsSimulator } from './simulators/UtilsSimulator'; +import * as contractUtils from './utils/address'; const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); const SOME_CONTRACT = contractUtils.createEitherTestContractAddress('SOME_CONTRACT'); const OTHER_CONTRACT = contractUtils.createEitherTestContractAddress('OTHER_CONTRACT'); -let contract: UtilsContractSimulator; +let contract: UtilsSimulator; describe('Utils', () => { - contract = new UtilsContractSimulator(); + contract = new UtilsSimulator(); describe('isKeyOrAddressZero', () => { it('should return zero for the zero address', () => { @@ -18,8 +18,14 @@ describe('Utils', () => { }); it('should not return zero for nonzero addresses', () => { - expect(contract.isKeyOrAddressZero(Z_SOME_KEY)).toBeFalsy; - expect(contract.isKeyOrAddressZero(SOME_CONTRACT)).toBeFalsy; + expect(contract.isKeyOrAddressZero(Z_SOME_KEY)).toBe(false); + expect(contract.isKeyOrAddressZero(SOME_CONTRACT)).toBe(false); + }); + + it('should return false for two different address types', () => { + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, SOME_CONTRACT)).toBe(false); + expect(contract.isKeyOrAddressZero(contractUtils.ZERO_KEY)).toBe(true); + expect(contract.isKeyOrAddressZero(contractUtils.ZERO_ADDRESS)).toBe(true); }); }); @@ -39,9 +45,5 @@ describe('Utils', () => { it('should return false for two different contract addresses', () => { expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, OTHER_CONTRACT)).toBeFalsy(); }); - - it('should return false for two different address types', () => { - expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, SOME_CONTRACT)).toBeFalsy(); - }); }); }); diff --git a/contracts/utils/src/test/utils/index.ts b/contracts/utils/src/test/utils/index.ts deleted file mode 100644 index 2668cc79..00000000 --- a/contracts/utils/src/test/utils/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { useCircuitContext as circuitContext } from './test'; -export { - pad, encodeToPK, encodeToAddress, createEitherTestUser, createEitherTestContractAddress, ZERO_KEY, ZERO_ADDRESS -} from './address'; diff --git a/contracts/utils/src/test/utils/test.ts b/contracts/utils/src/test/utils/test.ts index 940ed612..a8840104 100644 --- a/contracts/utils/src/test/utils/test.ts +++ b/contracts/utils/src/test/utils/test.ts @@ -6,7 +6,7 @@ import { QueryContext, emptyZswapLocalState, } from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types'; +import type { IContractSimulator } from '../types/test'; /** * Constructs a `CircuitContext` from the given state and sender information. diff --git a/contracts/initializable/src/witnesses/InitializableWitnesses.ts b/contracts/utils/src/witnesses/InitializableWitnesses.ts similarity index 100% rename from contracts/initializable/src/witnesses/InitializableWitnesses.ts rename to contracts/utils/src/witnesses/InitializableWitnesses.ts diff --git a/contracts/utils/src/witnesses/PausableWitnesses.ts b/contracts/utils/src/witnesses/PausableWitnesses.ts new file mode 100644 index 00000000..70ecc08f --- /dev/null +++ b/contracts/utils/src/witnesses/PausableWitnesses.ts @@ -0,0 +1,3 @@ +// This is how we type an empty object. +export type PausablePrivateState = Record; +export const PausableWitnesses = {}; diff --git a/contracts/utils/src/witnesses/index.ts b/contracts/utils/src/witnesses/index.ts deleted file mode 100644 index 1c74ba34..00000000 --- a/contracts/utils/src/witnesses/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../artifacts/utils/contract/index.cjs'; -export * from './UtilsWitnesses.js'; diff --git a/package.json b/package.json index 24105ba7..6c50ae60 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "workspaces": [ "compact", "contracts/erc20/", - "contracts/initializable/", "contracts/utils/" ], "scripts": { diff --git a/yarn.lock b/yarn.lock index 4ae6fb7c..19fc4fc5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1109,18 +1109,6 @@ __metadata: languageName: unknown linkType: soft -"@openzeppelin-midnight-contracts/initializable-contract@workspace:contracts/initializable": - version: 0.0.0-use.local - resolution: "@openzeppelin-midnight-contracts/initializable-contract@workspace:contracts/initializable" - dependencies: - "@midnight-ntwrk/compact": "workspace:*" - "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" - eslint: "npm:^8.52.0" - jest: "npm:^29.7.0" - typescript: "npm:^5.2.2" - languageName: unknown - linkType: soft - "@openzeppelin-midnight-contracts/utils-contract@workspace:^, @openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils" From 2b0e0ab794c52c67bc1e455690f6c121c81309b9 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 29 Apr 2025 16:36:52 -0500 Subject: [PATCH 072/282] Bump midnight-js, transition to biome, basic improvements (#35) * bump midnight-js * remove unused deps * remove eslint and prettier, add biome * run fmt * run lint * organize imports * remove dev deps from contracts/ * remove unused deps * update turbo and scripts * add clean script * add clean script * clean up test config * remove jest reporters * bump turbo to 2.5 * bump turbo * fix package names --- .dockerignore | 21 - biome.json | 38 + compact/.eslintrc.cjs | 2 +- compact/src/run-compactc.cjs | 16 +- compact/turbo.json | 4 +- contracts/erc721/.eslintignore | 1 - contracts/erc721/src/test/types/test.ts | 5 +- contracts/erc721/src/test/utils/test.ts | 21 +- contracts/utils/.eslintignore | 1 - contracts/utils/.eslintrc.cjs | 30 - contracts/utils/js-resolver.cjs | 18 +- contracts/utils/package.json | 13 +- .../utils/src/test/Initializable.test.ts | 26 +- contracts/utils/src/test/Pausable.test.ts | 4 +- .../test/simulators/InitializableSimulator.ts | 34 +- .../src/test/simulators/PausableSimulator.ts | 43 +- .../src/test/simulators/UtilsSimulator.ts | 28 +- contracts/utils/src/test/types/test.ts | 5 +- contracts/utils/src/test/utils.test.ts | 6 +- contracts/utils/src/test/utils/address.ts | 35 +- contracts/utils/src/test/utils/index.ts | 10 + contracts/utils/src/test/utils/test.ts | 21 +- package.json | 94 +- prettierrc.json | 6 - turbo.json | 108 +- yarn.lock | 3792 ++--------------- 26 files changed, 595 insertions(+), 3787 deletions(-) delete mode 100644 .dockerignore create mode 100644 biome.json delete mode 100644 contracts/erc721/.eslintignore delete mode 100644 contracts/utils/.eslintignore delete mode 100644 contracts/utils/.eslintrc.cjs create mode 100644 contracts/utils/src/test/utils/index.ts delete mode 100644 prettierrc.json diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 8ebba54f..00000000 --- a/.dockerignore +++ /dev/null @@ -1,21 +0,0 @@ -*.tsbuildinfo -result/ -.direnv/ -.idea/ -.env -*.log -examples/ -coverage/ -.github/ -.vscode/ -.yarn -flake.nix -flake.lock -renovate.json -*.Dockerfile -COMMIT_EDITMSG -FETCH_HEAD -ORIG_HEAD -NOTICE -LICENSE -HEAD diff --git a/biome.json b/biome.json new file mode 100644 index 00000000..656beeee --- /dev/null +++ b/biome.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": false, + "ignore": [ + "tsconfig.base.json", + "tsconfig*.json", + "*.compact", + "artifacts/*", + "coverage/*", + "dist/*", + "reports/*" + ] + }, + "formatter": { + "enabled": true, + "indentStyle": "space" + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "single" + } + } +} diff --git a/compact/.eslintrc.cjs b/compact/.eslintrc.cjs index fad1d320..32fa19b8 100644 --- a/compact/.eslintrc.cjs +++ b/compact/.eslintrc.cjs @@ -19,6 +19,6 @@ module.exports = { '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 '@typescript-eslint/no-floating-promises': 'warn', '@typescript-eslint/promise-function-async': 'off', - '@typescript-eslint/no-redeclare': 'off' + '@typescript-eslint/no-redeclare': 'off', }, }; diff --git a/compact/src/run-compactc.cjs b/compact/src/run-compactc.cjs index 69ca0eb4..dca2891f 100755 --- a/compact/src/run-compactc.cjs +++ b/compact/src/run-compactc.cjs @@ -1,7 +1,7 @@ #!/usr/bin/env node -const childProcess = require('child_process'); -const path = require('path'); +const childProcess = require('node:child_process'); +const path = require('node:path'); const [_node, _script, ...args] = process.argv; const COMPACT_HOME_ENV = process.env.COMPACT_HOME; @@ -9,15 +9,19 @@ const COMPACT_HOME_ENV = process.env.COMPACT_HOME; let compactPath; if (COMPACT_HOME_ENV != null) { compactPath = COMPACT_HOME_ENV; - console.log(`COMPACT_HOME env variable is set; using Compact from ${compactPath}`); + console.log( + `COMPACT_HOME env variable is set; using Compact from ${compactPath}`, + ); } else { compactPath = path.resolve(__dirname, '..', 'compactc'); - console.log(`COMPACT_HOME env variable is not set; using fetched compact from ${compactPath}`); + console.log( + `COMPACT_HOME env variable is not set; using fetched compact from ${compactPath}`, + ); } // yarn runs everything with node... const child = childProcess.spawn(path.resolve(compactPath, 'compactc'), args, { - stdio: 'inherit' + stdio: 'inherit', }); child.on('exit', (code, signal) => { if (code === 0) { @@ -25,4 +29,4 @@ child.on('exit', (code, signal) => { } else { process.exit(code ?? signal); } -}) +}); diff --git a/compact/turbo.json b/compact/turbo.json index 6d8bfaa0..9c9378a1 100644 --- a/compact/turbo.json +++ b/compact/turbo.json @@ -1,11 +1,11 @@ { "$schema": "https://turbo.build/schema.json", "extends": ["//"], - "pipeline": { + "tasks": { "build": { "outputs": ["compactc/**"], "env": ["COMPACT_HOME"], - "inputs": ["src/**"], + "inputs": ["src/**.cjs"], "cache": true } } diff --git a/contracts/erc721/.eslintignore b/contracts/erc721/.eslintignore deleted file mode 100644 index 327555cd..00000000 --- a/contracts/erc721/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -src/artifacts diff --git a/contracts/erc721/src/test/types/test.ts b/contracts/erc721/src/test/types/test.ts index 10fb6c98..7a909543 100644 --- a/contracts/erc721/src/test/types/test.ts +++ b/contracts/erc721/src/test/types/test.ts @@ -1,4 +1,7 @@ -import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; +import type { + CircuitContext, + ContractState, +} from '@midnight-ntwrk/compact-runtime'; /** * Generic interface for mock contract implementations. diff --git a/contracts/erc721/src/test/utils/test.ts b/contracts/erc721/src/test/utils/test.ts index a8840104..d467e572 100644 --- a/contracts/erc721/src/test/utils/test.ts +++ b/contracts/erc721/src/test/utils/test.ts @@ -1,10 +1,10 @@ import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - QueryContext, - emptyZswapLocalState, + type CircuitContext, + type CoinPublicKey, + type ContractAddress, + type ContractState, + QueryContext, + emptyZswapLocalState, } from '@midnight-ntwrk/compact-runtime'; import type { IContractSimulator } from '../types/test'; @@ -50,10 +50,11 @@ export function useCircuitContext

( * @returns A new `CircuitContext` with the sender and updated context values. * @todo TODO: Move this utility to a generic package for broader reuse across contracts. */ -export function useCircuitContextSender>( - contract: C, - sender: CoinPublicKey, -): CircuitContext

{ +export function useCircuitContextSender< + P, + L, + C extends IContractSimulator, +>(contract: C, sender: CoinPublicKey): CircuitContext

{ const currentPrivateState = contract.getCurrentPrivateState(); const originalState = contract.getCurrentContractState(); const contractAddress = contract.contractAddress; diff --git a/contracts/utils/.eslintignore b/contracts/utils/.eslintignore deleted file mode 100644 index 327555cd..00000000 --- a/contracts/utils/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -src/artifacts diff --git a/contracts/utils/.eslintrc.cjs b/contracts/utils/.eslintrc.cjs deleted file mode 100644 index 581f1d49..00000000 --- a/contracts/utils/.eslintrc.cjs +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - node: true, - jest: true, - }, - extends: [ - 'standard-with-typescript', - 'plugin:prettier/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - overrides: [], - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['tsconfig.json'], - }, - rules: { - '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 - '@typescript-eslint/no-floating-promises': 'warn', - '@typescript-eslint/promise-function-async': 'off', - '@typescript-eslint/no-redeclare': 'off', - '@typescript-eslint/no-invalid-void-type': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/consistent-type-definitions': 'off' - }, -}; diff --git a/contracts/utils/js-resolver.cjs b/contracts/utils/js-resolver.cjs index cc9ed285..19b6f50c 100644 --- a/contracts/utils/js-resolver.cjs +++ b/contracts/utils/js-resolver.cjs @@ -1,16 +1,20 @@ const jsResolver = (path, options) => { - const jsExtRegex = /\.js$/i - const resolver = options.defaultResolver - if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { + const jsExtRegex = /\.js$/i; + const resolver = options.defaultResolver; + if ( + jsExtRegex.test(path) && + !options.basedir.includes('node_modules') && + !path.includes('node_modules') + ) { const newPath = path.replace(jsExtRegex, '.ts'); try { - return resolver(newPath, options) + return resolver(newPath, options); } catch { // use default resolver } } - return resolver(path, options) -} + return resolver(path, options); +}; -module.exports = jsResolver +module.exports = jsResolver; diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 82019c84..f5a0217c 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -1,5 +1,5 @@ { - "name": "@openzeppelin-midnight-contracts/erc20-contract", + "name": "@openzeppelin-midnight/utils", "type": "module", "main": "dist/index.js", "module": "dist/index.js", @@ -15,17 +15,20 @@ "scripts": { "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", "test": "NODE_OPTIONS=--experimental-vm-modules jest", - "prepack": "yarn build", "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/{Initializable,Pausable,Utils}.compact ./dist", - "lint": "eslint src", - "typecheck": "tsc -p tsconfig.json --noEmit" + "typecheck": "tsc -p tsconfig.json --noEmit", + "types": "tsc -p tsconfig.json --noEmit", + "fmt": "biome format", + "fmt:fix": "biome format --write", + "lint": "biome lint", + "lint:fix": "biome check --write", + "clean": "git clean -fXd" }, "dependencies": { "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" }, "devDependencies": { "@midnight-ntwrk/compact": "workspace:*", - "eslint": "^8.52.0", "jest": "^29.7.0", "typescript": "^5.2.2" } diff --git a/contracts/utils/src/test/Initializable.test.ts b/contracts/utils/src/test/Initializable.test.ts index 5a306087..fdb8783b 100644 --- a/contracts/utils/src/test/Initializable.test.ts +++ b/contracts/utils/src/test/Initializable.test.ts @@ -1,4 +1,4 @@ -import { it, describe, expect } from '@jest/globals'; +import { describe, expect, it } from '@jest/globals'; import { InitializableSimulator } from './simulators/InitializableSimulator'; let initializable: InitializableSimulator; @@ -10,25 +10,31 @@ describe('Initializable', () => { it('should generate the initial ledger state deterministically', () => { const initializable2 = new InitializableSimulator(); - expect(initializable.getCurrentPublicState()).toEqual(initializable2.getCurrentPublicState()); + expect(initializable.getCurrentPublicState()).toEqual( + initializable2.getCurrentPublicState(), + ); }); describe('initialize', () => { it('should not be initialized', () => { - expect(initializable.getCurrentPublicState().initializable_IsInitialized).toEqual(false); + expect( + initializable.getCurrentPublicState().initializable_IsInitialized, + ).toEqual(false); }); it('should initialize', () => { initializable.initialize(); - expect(initializable.getCurrentPublicState().initializable_IsInitialized).toEqual(true); - }); + expect( + initializable.getCurrentPublicState().initializable_IsInitialized, + ).toEqual(true); }); + }); - it('should fail when re-initialized', () => { - expect(() => { - initializable.initialize(); - initializable.initialize(); - }).toThrow('Initializable: contract already initialized'); + it('should fail when re-initialized', () => { + expect(() => { + initializable.initialize(); + initializable.initialize(); + }).toThrow('Initializable: contract already initialized'); }); describe('assertInitialized', () => { diff --git a/contracts/utils/src/test/Pausable.test.ts b/contracts/utils/src/test/Pausable.test.ts index fdbb2fac..d969b431 100644 --- a/contracts/utils/src/test/Pausable.test.ts +++ b/contracts/utils/src/test/Pausable.test.ts @@ -1,4 +1,4 @@ -import { it, describe, expect } from '@jest/globals'; +import { describe, expect, it } from '@jest/globals'; import { PausableSimulator } from './simulators/PausableSimulator'; let pausable: PausableSimulator; @@ -41,7 +41,7 @@ describe('Pausable', () => { }); it('should not throw when calling assertPaused', () => { - pausable.assertPaused(); + pausable.assertPaused(); }); it('should throw when calling assertNotPaused', () => { diff --git a/contracts/utils/src/test/simulators/InitializableSimulator.ts b/contracts/utils/src/test/simulators/InitializableSimulator.ts index 67810eec..fa8ad2f2 100644 --- a/contracts/utils/src/test/simulators/InitializableSimulator.ts +++ b/contracts/utils/src/test/simulators/InitializableSimulator.ts @@ -1,7 +1,20 @@ -import { type CircuitContext, type ContractState, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; -import { Contract as MockInitializable, type Ledger, ledger } from '../../artifacts/MockInitializable/contract/index.cjs'; +import { + type CircuitContext, + type ContractState, + QueryContext, + constructorContext, + sampleContractAddress, +} from '@midnight-ntwrk/compact-runtime'; +import { + type Ledger, + Contract as MockInitializable, + ledger, +} from '../../artifacts/MockInitializable/contract/index.cjs'; +import { + type InitializablePrivateState, + InitializableWitnesses, +} from '../../witnesses/InitializableWitnesses'; import type { IContractSimulator } from '../types/test'; -import { InitializablePrivateState, InitializableWitnesses } from '../../witnesses/InitializableWitnesses'; /** * @description A simulator implementation of an utils contract for testing purposes. @@ -31,9 +44,7 @@ export class InitializableSimulator currentPrivateState, currentContractState, currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)) - ); + } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); this.circuitContext = { currentPrivateState, currentZswapLocalState, @@ -75,7 +86,9 @@ export class InitializableSimulator * @returns None. */ public initialize() { - this.circuitContext = this.contract.impureCircuits.initialize(this.circuitContext).context; + this.circuitContext = this.contract.impureCircuits.initialize( + this.circuitContext, + ).context; } /** @@ -84,7 +97,8 @@ export class InitializableSimulator * @throws Will throw "Initializable: contract not initialized" if the contract is not initialized. */ public assertInitialized() { - return this.contract.impureCircuits.assertInitialized(this.circuitContext).result; + return this.contract.impureCircuits.assertInitialized(this.circuitContext) + .result; } /** @@ -93,6 +107,8 @@ export class InitializableSimulator * @throws Will throw "Initializable: contract already initialized" if the contract is already initialized. */ public assertNotInitialized() { - return this.contract.impureCircuits.assertNotInitialized(this.circuitContext).result; + return this.contract.impureCircuits.assertNotInitialized( + this.circuitContext, + ).result; } } diff --git a/contracts/utils/src/test/simulators/PausableSimulator.ts b/contracts/utils/src/test/simulators/PausableSimulator.ts index 719a1b61..034d84a4 100644 --- a/contracts/utils/src/test/simulators/PausableSimulator.ts +++ b/contracts/utils/src/test/simulators/PausableSimulator.ts @@ -1,7 +1,20 @@ -import { type CircuitContext, type ContractState, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; -import { Contract as MockPausable, type Ledger, ledger } from '../../artifacts/MockPausable/contract/index.cjs'; +import { + type CircuitContext, + type ContractState, + QueryContext, + constructorContext, + sampleContractAddress, +} from '@midnight-ntwrk/compact-runtime'; +import { + type Ledger, + Contract as MockPausable, + ledger, +} from '../../artifacts/MockPausable/contract/index.cjs'; +import { + type PausablePrivateState, + PausableWitnesses, +} from '../../witnesses/PausableWitnesses'; import type { IContractSimulator } from '../types/test'; -import { PausablePrivateState, PausableWitnesses } from '../../witnesses/PausableWitnesses'; /** * @description A simulator implementation of an utils contract for testing purposes. @@ -24,16 +37,12 @@ export class PausableSimulator * @description Initializes the mock contract. */ constructor() { - this.contract = new MockPausable( - PausableWitnesses, - ); + this.contract = new MockPausable(PausableWitnesses); const { currentPrivateState, currentContractState, currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)) - ); + } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); this.circuitContext = { currentPrivateState, currentZswapLocalState, @@ -83,7 +92,9 @@ export class PausableSimulator * @returns None. */ public assertPaused() { - this.circuitContext = this.contract.impureCircuits.assertPaused(this.circuitContext).context; + this.circuitContext = this.contract.impureCircuits.assertPaused( + this.circuitContext, + ).context; } /** @@ -91,7 +102,9 @@ export class PausableSimulator * @returns None. */ public assertNotPaused() { - this.circuitContext = this.contract.impureCircuits.assertNotPaused(this.circuitContext).context; + this.circuitContext = this.contract.impureCircuits.assertNotPaused( + this.circuitContext, + ).context; } /** @@ -99,7 +112,9 @@ export class PausableSimulator * @returns None. */ public pause() { - this.circuitContext = this.contract.impureCircuits.pause(this.circuitContext).context; + this.circuitContext = this.contract.impureCircuits.pause( + this.circuitContext, + ).context; } /** @@ -107,6 +122,8 @@ export class PausableSimulator * @returns None. */ public unpause() { - this.circuitContext = this.contract.impureCircuits.unpause(this.circuitContext).context; + this.circuitContext = this.contract.impureCircuits.unpause( + this.circuitContext, + ).context; } } diff --git a/contracts/utils/src/test/simulators/UtilsSimulator.ts b/contracts/utils/src/test/simulators/UtilsSimulator.ts index dfacc17e..a09d7026 100644 --- a/contracts/utils/src/test/simulators/UtilsSimulator.ts +++ b/contracts/utils/src/test/simulators/UtilsSimulator.ts @@ -6,15 +6,18 @@ import { } from '@midnight-ntwrk/compact-runtime'; import { sampleContractAddress } from '@midnight-ntwrk/zswap'; import { + type ContractAddress, + type Either, type Ledger, Contract as MockUtils, + type ZswapCoinPublicKey, ledger, - Either, - ZswapCoinPublicKey, - ContractAddress, } from '../../artifacts/MockUtils/contract/index.cjs'; // Combined imports +import { + type UtilsPrivateState, + UtilsWitnesses, +} from '../../witnesses/UtilsWitnesses'; import type { IContractSimulator } from '../types/test'; -import { UtilsPrivateState, UtilsWitnesses } from '../../witnesses/UtilsWitnesses'; /** * @description A simulator implementation of an utils contract for testing purposes. @@ -42,16 +45,12 @@ export class UtilsSimulator * @description Initializes the mock contract. */ constructor() { - this.contract = new MockUtils( - UtilsWitnesses, - ); + this.contract = new MockUtils(UtilsWitnesses); const { currentPrivateState, currentContractState, currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)) - ); + } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); this.circuitContext = { currentPrivateState, currentZswapLocalState, @@ -93,8 +92,13 @@ export class UtilsSimulator * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @returns Returns true if `keyOrAddress` is zero. */ - public isKeyOrAddressZero(keyOrAddress: Either): boolean { - return this.contract.circuits.isKeyOrAddressZero(this.circuitContext, keyOrAddress).result; + public isKeyOrAddressZero( + keyOrAddress: Either, + ): boolean { + return this.contract.circuits.isKeyOrAddressZero( + this.circuitContext, + keyOrAddress, + ).result; } /** diff --git a/contracts/utils/src/test/types/test.ts b/contracts/utils/src/test/types/test.ts index 10fb6c98..7a909543 100644 --- a/contracts/utils/src/test/types/test.ts +++ b/contracts/utils/src/test/types/test.ts @@ -1,4 +1,7 @@ -import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; +import type { + CircuitContext, + ContractState, +} from '@midnight-ntwrk/compact-runtime'; /** * Generic interface for mock contract implementations. diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 6d1e0e4b..40360a45 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -13,8 +13,10 @@ describe('Utils', () => { describe('isKeyOrAddressZero', () => { it('should return zero for the zero address', () => { - expect(contract.isKeyOrAddressZero(contractUtils.ZERO_KEY)).toBeTruthy; - expect(contract.isKeyOrAddressZero(contractUtils.ZERO_ADDRESS)).toBeTruthy; + expect(contract.isKeyOrAddressZero(contractUtils.ZERO_KEY)).toBe(true); + expect(contract.isKeyOrAddressZero(contractUtils.ZERO_ADDRESS)).toBe( + true, + ); }); it('should not return zero for nonzero addresses', () => { diff --git a/contracts/utils/src/test/utils/address.ts b/contracts/utils/src/test/utils/address.ts index f6255d60..d4ac78a7 100644 --- a/contracts/utils/src/test/utils/address.ts +++ b/contracts/utils/src/test/utils/address.ts @@ -1,8 +1,11 @@ +import { + convert_bigint_to_Uint8Array, + encodeCoinPublicKey, +} from '@midnight-ntwrk/compact-runtime'; import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import * as Compact from '../../artifacts/MockUtils/contract/index.cjs'; -import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; +import type * as Compact from '../../artifacts/MockUtils/contract/index.cjs'; -const PREFIX_ADDRESS = "0200"; +const PREFIX_ADDRESS = '0200'; export const pad = (s: string, n: number): Uint8Array => { const encoder = new TextEncoder(); @@ -13,7 +16,7 @@ export const pad = (s: string, n: number): Uint8Array => { const paddedArray = new Uint8Array(n); paddedArray.set(utf8Bytes); return paddedArray; -} +}; /** * @description Generates ZswapCoinPublicKey from `str` for testing purposes. @@ -23,7 +26,7 @@ export const pad = (s: string, n: number): Uint8Array => { export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { const toHex = Buffer.from(str, 'ascii').toString('hex'); return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; -} +}; /** * @description Generates ContractAddress from `str` for testing purposes. @@ -35,7 +38,7 @@ export const encodeToAddress = (str: string): Compact.ContractAddress => { const toHex = Buffer.from(str, 'ascii').toString('hex'); const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); return { bytes: encodeContractAddress(fullAddress) }; -} +}; /** * @description Generates an Either object for ZswapCoinPublicKey for testing. @@ -47,9 +50,9 @@ export const createEitherTestUser = (str: string) => { return { is_left: true, left: encodeToPK(str), - right: encodeToAddress('') - } -} + right: encodeToAddress(''), + }; +}; /** * @description Generates an Either object for ContractAddress for testing. @@ -61,18 +64,18 @@ export const createEitherTestContractAddress = (str: string) => { return { is_left: false, left: encodeToPK(''), - right: encodeToAddress(str) - } -} + right: encodeToAddress(str), + }; +}; export const ZERO_KEY = { is_left: true, left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, - right: encodeToAddress('') -} + right: encodeToAddress(''), +}; export const ZERO_ADDRESS = { is_left: false, left: encodeToPK(''), - right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) } -} + right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, +}; diff --git a/contracts/utils/src/test/utils/index.ts b/contracts/utils/src/test/utils/index.ts new file mode 100644 index 00000000..b8e9585d --- /dev/null +++ b/contracts/utils/src/test/utils/index.ts @@ -0,0 +1,10 @@ +export { useCircuitContext as circuitContext } from './test'; +export { + pad, + encodeToPK, + encodeToAddress, + createEitherTestUser, + createEitherTestContractAddress, + ZERO_KEY, + ZERO_ADDRESS, +} from './address'; diff --git a/contracts/utils/src/test/utils/test.ts b/contracts/utils/src/test/utils/test.ts index a8840104..d467e572 100644 --- a/contracts/utils/src/test/utils/test.ts +++ b/contracts/utils/src/test/utils/test.ts @@ -1,10 +1,10 @@ import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - QueryContext, - emptyZswapLocalState, + type CircuitContext, + type CoinPublicKey, + type ContractAddress, + type ContractState, + QueryContext, + emptyZswapLocalState, } from '@midnight-ntwrk/compact-runtime'; import type { IContractSimulator } from '../types/test'; @@ -50,10 +50,11 @@ export function useCircuitContext

( * @returns A new `CircuitContext` with the sender and updated context values. * @todo TODO: Move this utility to a generic package for broader reuse across contracts. */ -export function useCircuitContextSender>( - contract: C, - sender: CoinPublicKey, -): CircuitContext

{ +export function useCircuitContextSender< + P, + L, + C extends IContractSimulator, +>(contract: C, sender: CoinPublicKey): CircuitContext

{ const currentPrivateState = contract.getCurrentPrivateState(); const originalState = contract.getCurrentContractState(); const contractAddress = contract.contractAddress; diff --git a/package.json b/package.json index 6c50ae60..93bbacc3 100644 --- a/package.json +++ b/package.json @@ -1,62 +1,36 @@ { - "packageManager": "yarn@4.1.0", - "workspaces": [ - "compact", - "contracts/erc20/", - "contracts/utils/" - ], - "scripts": { - "compact": "turbo run compact", - "build": "turbo run build", - "lint": "turbo run lint" - }, - "resolutions": { - "@midnight-ntwrk/compact-runtime/@midnight-ntwrk/onchain-runtime": "^0.2.2", - "@midnight-ntwrk/zswap": "^3.0.2" - }, - "dependencies": { - "@midnight-ntwrk/compact-runtime": "^0.7.0", - "@midnight-ntwrk/dapp-connector-api": "^1.2.2", - "@midnight-ntwrk/ledger": "^3.0.2", - "@midnight-ntwrk/midnight-js-contracts": "0.2.5", - "@midnight-ntwrk/midnight-js-fetch-zk-config-provider": "0.2.5", - "@midnight-ntwrk/midnight-js-http-client-proof-provider": "0.2.5", - "@midnight-ntwrk/midnight-js-indexer-public-data-provider": "0.2.5", - "@midnight-ntwrk/midnight-js-level-private-state-provider": "0.2.5", - "@midnight-ntwrk/midnight-js-network-id": "0.2.5", - "@midnight-ntwrk/midnight-js-node-zk-config-provider": "0.2.5", - "@midnight-ntwrk/midnight-js-types": "0.2.5", - "@midnight-ntwrk/midnight-js-utils": "0.2.5", - "@midnight-ntwrk/wallet": "^3.7.3", - "@midnight-ntwrk/wallet-api": "^3.5.0", - "fp-ts": "^2.16.1", - "io-ts": "^2.2.20", - "pino": "^8.16.0", - "pino-pretty": "^10.2.3", - "rxjs": "^7.8.1" - }, - "devDependencies": { - "@types/jest": "^29.5.6", - "@types/node": "^18.18.6", - "@typescript-eslint/eslint-plugin": "^6.8.0", - "@typescript-eslint/parser": "^6.8.0", - "eslint": "^8.52.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-n": "^16.2.0", - "eslint-plugin-prettier": "^5.0.1", - "eslint-plugin-promise": "^6.1.1", - "fast-check": "^3.15.0", - "jest": "^29.7.0", - "jest-fast-check": "^2.0.0", - "jest-gh-md-reporter": "^0.0.2", - "jest-html-reporters": "^3.1.4", - "jest-junit": "^16.0.0", - "prettier": "^3.0.3", - "testcontainers": "^10.3.2", - "ts-jest": "^29.1.1", - "ts-node": "^10.9.1", - "turbo": "^1.10.16", - "typescript": "^5.2.2" - } + "packageManager": "yarn@4.1.0", + "workspaces": [ + "compact", + "contracts/erc20/", + "contracts/utils/" + ], + "scripts": { + "compact": "turbo run compact", + "build": "turbo run build", + "test": "turbo run test", + "fmt": "turbo run fmt", + "fmt:fix": "turbo run fmt:fix", + "lint": "turbo run lint", + "lint:fix": "turbo run lint:fix", + "types": "turbo run types", + "clean": "turbo run clean" + }, + "dependencies": { + "@midnight-ntwrk/compact-runtime": "^0.7.0" + }, + "devDependencies": { + "@biomejs/biome": "1.9.4", + "@midnight-ntwrk/ledger": "^3.0.6", + "@midnight-ntwrk/zswap": "^3.0.6", + "@types/jest": "^29.5.6", + "@types/node": "^18.18.6", + "fast-check": "^3.15.0", + "jest": "^29.7.0", + "jest-fast-check": "^2.0.0", + "ts-jest": "^29.1.1", + "ts-node": "^10.9.1", + "turbo": "^2.5.1", + "typescript": "^5.2.2" + } } diff --git a/prettierrc.json b/prettierrc.json deleted file mode 100644 index 4eb15403..00000000 --- a/prettierrc.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "semi": true, - "trailingComma": "all", - "singleQuote": true, - "printWidth": 130 - } diff --git a/turbo.json b/turbo.json index b539bd83..0940f33c 100644 --- a/turbo.json +++ b/turbo.json @@ -1,66 +1,70 @@ { "$schema": "https://turbo.build/schema.json", - "globalDependencies": [ - ".prettierrc.json" - ], - "pipeline": { - "typecheck": { - "dependsOn": ["^build", "compact"], - "inputs": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.mts", "tsconfig.json"], - "outputMode": "new-only", - "outputs": [] - }, + "tasks": { "compact": { - "dependsOn": ["^build"], - "env": ["COMPACT_HOME"], - "inputs": ["src/**/*.compact"], - "outputMode": "new-only", - "outputs": ["src/artifacts/**", "src/gen/**", "gen/**"] - }, - "build": { - "dependsOn": ["^build", "compact", "typecheck"], - "outputMode": "new-only", - "inputs": ["src/**/*.ts", "src/**/*.mts", "src/**/*.tsx", "!src/**/*.test.ts", "!tests/**/*.ts", "tsconfig.json", "tsconfig.build.json", ".env"], - "outputs": ["dist/**"] + "env": [ + "COMPACT_HOME" + ], + "inputs": [ + "src/**/*.compact" + ], + "outputLogs": "new-only", + "outputs": [ + "src/artifacts/**", + "src/gen/**", + "gen/**" + ] }, - "build-storybook": { - "dependsOn": ["^build", "typecheck"], - "outputMode": "new-only", - "inputs": ["src/**/*.ts", "src/**/*.mts", "src/**/*.tsx", "!src/**/*.test.ts", "!tests/**/*.ts", "tsconfig.json", "tsconfig.build.json", ".env", "vite.config.ts", ".storybook/**"], - "outputs": ["storybook-static/**"] + "test": { + "outputs": [], + "cache": false }, - "lint": { - "outputMode": "new-only", - "dependsOn": ["compact", "^build", "typecheck"], - "inputs": ["src/**/*.ts", "src/**/*.mts", "src/**/*.tsx", ".eslintrc.cjs"] + "build": { + "dependsOn": [ + "^build", + "compact" + ], + "env": [ + "COMPACT_HOME" + ], + "inputs": [ + "src/**/*.ts", + "!src/**/*.test.ts", + "!tests/**/*.ts", + "tsconfig.json", + "tsconfig.build.json", + ".env" + ], + "outputs": [ + "dist/**" + ] }, - "test": { - "outputMode": "new-only", - "dependsOn": ["^build", "compact", "typecheck"], - "inputs": ["src/**/*.ts", "src/**/*.mts", "src/**/*.tsx", "jest.config.ts", "tsconfig.json", "tsconfig.test.json", "test-compose.yml"], - "outputs": ["reports/**"] + "types": { + "outputs": [], + "cache": false, + "dependsOn": [ + "compact" + ] }, - "check": { - "outputMode": "new-only", - "dependsOn": ["build", "lint", "test", "build-storybook"] + "fmt": { + "outputs": [], + "cache": false }, - "test-e2e": { - "outputMode": "new-only", - "dependsOn": ["build", "compact"] + "fmt:fix": { + "outputs": [], + "cache": false }, - "start": { - "cache": false, - "persistent": true, - "dependsOn": ["build"] + "lint": { + "outputs": [], + "cache": false }, - "dev": { - "cache": false, - "persistent": true + "lint:fix": { + "outputs": [], + "cache": false }, - "storybook": { - "cache": false, - "persistent": true, - "dependsOn": ["build"] + "clean": { + "outputs": [], + "cache": false } } } diff --git a/yarn.lock b/yarn.lock index 19fc4fc5..4b43ba7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,42 +15,6 @@ __metadata: languageName: node linkType: hard -"@apollo/client@npm:^3.8.2": - version: 3.13.1 - resolution: "@apollo/client@npm:3.13.1" - dependencies: - "@graphql-typed-document-node/core": "npm:^3.1.1" - "@wry/caches": "npm:^1.0.0" - "@wry/equality": "npm:^0.5.6" - "@wry/trie": "npm:^0.5.0" - graphql-tag: "npm:^2.12.6" - hoist-non-react-statics: "npm:^3.3.2" - optimism: "npm:^0.18.0" - prop-types: "npm:^15.7.2" - rehackt: "npm:^0.1.0" - symbol-observable: "npm:^4.0.0" - ts-invariant: "npm:^0.10.3" - tslib: "npm:^2.3.0" - zen-observable-ts: "npm:^1.2.5" - peerDependencies: - graphql: ^15.0.0 || ^16.0.0 - graphql-ws: ^5.5.5 || ^6.0.3 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc - subscriptions-transport-ws: ^0.9.0 || ^0.11.0 - peerDependenciesMeta: - graphql-ws: - optional: true - react: - optional: true - react-dom: - optional: true - subscriptions-transport-ws: - optional: true - checksum: 10/d3744a5416c7ba33057b1ed247fa4b30da167a6b490898968e6e03870424906c3b4b1910829dc5b26622393e3f203b6ad26e7f6a2c2e9505dc0f9e915432482a - languageName: node - linkType: hard - "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.26.2": version: 7.26.2 resolution: "@babel/code-frame@npm:7.26.2" @@ -413,13 +377,6 @@ __metadata: languageName: node linkType: hard -"@balena/dockerignore@npm:^1.0.2": - version: 1.0.2 - resolution: "@balena/dockerignore@npm:1.0.2" - checksum: 10/13d654fdd725008577d32e721c720275bdc48f72bce612326363d5bed449febbed856c517a0b23c7c40d87cb531e63432804550b4ecc13e365d26fee38fb6c8a - languageName: node - linkType: hard - "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -427,6 +384,97 @@ __metadata: languageName: node linkType: hard +"@biomejs/biome@npm:1.9.4": + version: 1.9.4 + resolution: "@biomejs/biome@npm:1.9.4" + dependencies: + "@biomejs/cli-darwin-arm64": "npm:1.9.4" + "@biomejs/cli-darwin-x64": "npm:1.9.4" + "@biomejs/cli-linux-arm64": "npm:1.9.4" + "@biomejs/cli-linux-arm64-musl": "npm:1.9.4" + "@biomejs/cli-linux-x64": "npm:1.9.4" + "@biomejs/cli-linux-x64-musl": "npm:1.9.4" + "@biomejs/cli-win32-arm64": "npm:1.9.4" + "@biomejs/cli-win32-x64": "npm:1.9.4" + dependenciesMeta: + "@biomejs/cli-darwin-arm64": + optional: true + "@biomejs/cli-darwin-x64": + optional: true + "@biomejs/cli-linux-arm64": + optional: true + "@biomejs/cli-linux-arm64-musl": + optional: true + "@biomejs/cli-linux-x64": + optional: true + "@biomejs/cli-linux-x64-musl": + optional: true + "@biomejs/cli-win32-arm64": + optional: true + "@biomejs/cli-win32-x64": + optional: true + bin: + biome: bin/biome + checksum: 10/bd8ff8fb4dc0581bd60a9b9ac28d0cd03ba17c6a1de2ab6228b7fda582079594ceee774f47e41aac2fc6d35de1637def2e32ef2e58fa24e22d1b24ef9ee5cefa + languageName: node + linkType: hard + +"@biomejs/cli-darwin-arm64@npm:1.9.4": + version: 1.9.4 + resolution: "@biomejs/cli-darwin-arm64@npm:1.9.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@biomejs/cli-darwin-x64@npm:1.9.4": + version: 1.9.4 + resolution: "@biomejs/cli-darwin-x64@npm:1.9.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@biomejs/cli-linux-arm64-musl@npm:1.9.4": + version: 1.9.4 + resolution: "@biomejs/cli-linux-arm64-musl@npm:1.9.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@biomejs/cli-linux-arm64@npm:1.9.4": + version: 1.9.4 + resolution: "@biomejs/cli-linux-arm64@npm:1.9.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@biomejs/cli-linux-x64-musl@npm:1.9.4": + version: 1.9.4 + resolution: "@biomejs/cli-linux-x64-musl@npm:1.9.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@biomejs/cli-linux-x64@npm:1.9.4": + version: 1.9.4 + resolution: "@biomejs/cli-linux-x64@npm:1.9.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@biomejs/cli-win32-arm64@npm:1.9.4": + version: 1.9.4 + resolution: "@biomejs/cli-win32-arm64@npm:1.9.4" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@biomejs/cli-win32-x64@npm:1.9.4": + version: 1.9.4 + resolution: "@biomejs/cli-win32-x64@npm:1.9.4" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@cspotcode/source-map-support@npm:^0.8.0": version: 0.8.1 resolution: "@cspotcode/source-map-support@npm:0.8.1" @@ -436,17 +484,7 @@ __metadata: languageName: node linkType: hard -"@dao-xyz/borsh@npm:^5.1.5": - version: 5.2.3 - resolution: "@dao-xyz/borsh@npm:5.2.3" - dependencies: - "@protobufjs/float": "npm:^1.0.2" - "@protobufjs/utf8": "npm:^1.1.0" - checksum: 10/87480526dd501ee5726aa39dccb27018e82e00a0d21ec7eaed6f23dd80eb94662f2395b17b09b44cd34ff06ffde9458d7734940e42cf5e7b5daf2c7bc03cfe3a - languageName: node - linkType: hard - -"@eslint-community/eslint-utils@npm:^4.1.2, @eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": +"@eslint-community/eslint-utils@npm:^4.2.0": version: 4.4.1 resolution: "@eslint-community/eslint-utils@npm:4.4.1" dependencies: @@ -457,7 +495,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.11.0, @eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": +"@eslint-community/regexpp@npm:^4.6.1": version: 4.12.1 resolution: "@eslint-community/regexpp@npm:4.12.1" checksum: 10/c08f1dd7dd18fbb60bdd0d85820656d1374dd898af9be7f82cb00451313402a22d5e30569c150315b4385907cdbca78c22389b2a72ab78883b3173be317620cc @@ -488,22 +526,6 @@ __metadata: languageName: node linkType: hard -"@fastify/busboy@npm:^2.0.0": - version: 2.1.1 - resolution: "@fastify/busboy@npm:2.1.1" - checksum: 10/2bb8a7eca8289ed14c9eb15239bc1019797454624e769b39a0b90ed204d032403adc0f8ed0d2aef8a18c772205fa7808cf5a1b91f21c7bfc7b6032150b1062c5 - languageName: node - linkType: hard - -"@graphql-typed-document-node/core@npm:^3.1.1": - version: 3.2.0 - resolution: "@graphql-typed-document-node/core@npm:3.2.0" - peerDependencies: - graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 10/fa44443accd28c8cf4cb96aaaf39d144a22e8b091b13366843f4e97d19c7bfeaf609ce3c7603a4aeffe385081eaf8ea245d078633a7324c11c5ec4b2011bb76d - languageName: node - linkType: hard - "@humanwhocodes/config-array@npm:^0.13.0": version: 0.13.0 resolution: "@humanwhocodes/config-array@npm:0.13.0" @@ -865,7 +887,7 @@ __metadata: languageName: node linkType: hard -"@midnight-ntwrk/compact@workspace:*, @midnight-ntwrk/compact@workspace:compact": +"@midnight-ntwrk/compact@workspace:compact": version: 0.0.0-use.local resolution: "@midnight-ntwrk/compact@workspace:compact" dependencies: @@ -877,159 +899,21 @@ __metadata: languageName: unknown linkType: soft -"@midnight-ntwrk/dapp-connector-api@npm:^1.2.2": - version: 1.2.3 - resolution: "@midnight-ntwrk/dapp-connector-api@npm:1.2.3" - dependencies: - "@midnight-ntwrk/wallet-api": "npm:^3.4.2" - "@midnight-ntwrk/zswap": "npm:^3.0.2" - ts-custom-error: "npm:^3.3.1" - checksum: 10/2ecc68a486fa535b42361ba89e1703485ed25c533ee4e312bcd16bde83e990ad37c4f928f08531954da172a9773d0561473154c4feb034915779a491f8816ce0 - languageName: node - linkType: hard - -"@midnight-ntwrk/ledger@npm:^3.0.2": +"@midnight-ntwrk/ledger@npm:^3.0.6": version: 3.0.6 resolution: "@midnight-ntwrk/ledger@npm:3.0.6" checksum: 10/644fac9ea7b47c8d0c8ea437e18e2362746701e2fedba3f6fa9a08dcea1f283c05336d9def60403e72055baa5a1e841f971a858ae3133b577a3f12518a48c753 languageName: node linkType: hard -"@midnight-ntwrk/midnight-js-contracts@npm:0.2.5": - version: 0.2.5 - resolution: "@midnight-ntwrk/midnight-js-contracts@npm:0.2.5" - dependencies: - "@midnight-ntwrk/midnight-js-network-id": "npm:0.2.5" - "@midnight-ntwrk/midnight-js-types": "npm:0.2.5" - "@midnight-ntwrk/midnight-js-utils": "npm:0.2.5" - checksum: 10/ad584d7874f7539c6ce2fc8057ab86bf4da8021c935c0e6be569218d2abd64f7e44ef68e7c98da86a87f1d8389fb14676b30a9c15e4e1b0a5daba3fe92cf9b29 - languageName: node - linkType: hard - -"@midnight-ntwrk/midnight-js-fetch-zk-config-provider@npm:0.2.5": - version: 0.2.5 - resolution: "@midnight-ntwrk/midnight-js-fetch-zk-config-provider@npm:0.2.5" - dependencies: - "@midnight-ntwrk/midnight-js-types": "npm:0.2.5" - cross-fetch: "npm:^4.0.0" - checksum: 10/aa867a7e57b1a854d7aa70fbdf6e27d3ccda6388da9e4c27d5430344b7fe0d10c6ae357a47e20e61c559539378114addba562cf24c503ee25f93048c416d5942 - languageName: node - linkType: hard - -"@midnight-ntwrk/midnight-js-http-client-proof-provider@npm:0.2.5": - version: 0.2.5 - resolution: "@midnight-ntwrk/midnight-js-http-client-proof-provider@npm:0.2.5" - dependencies: - "@dao-xyz/borsh": "npm:^5.1.5" - "@midnight-ntwrk/midnight-js-network-id": "npm:0.2.5" - "@midnight-ntwrk/midnight-js-types": "npm:0.2.5" - cross-fetch: "npm:^4.0.0" - lodash: "npm:^4.17.21" - checksum: 10/8e51e01363f506e67001944f17c249fac8ac16756c2405002431d7591dba1a84442a4c086a92e3ffc3a9c68028ad54d28902e22f4399e16942214f0c95b1fb69 - languageName: node - linkType: hard - -"@midnight-ntwrk/midnight-js-indexer-public-data-provider@npm:0.2.5": - version: 0.2.5 - resolution: "@midnight-ntwrk/midnight-js-indexer-public-data-provider@npm:0.2.5" - dependencies: - "@apollo/client": "npm:^3.8.2" - "@midnight-ntwrk/midnight-js-network-id": "npm:0.2.5" - "@midnight-ntwrk/midnight-js-types": "npm:0.2.5" - buffer: "npm:^6.0.3" - cross-fetch: "npm:^4.0.0" - graphql: "npm:^16.8.0" - graphql-ws: "npm:^5.14.0" - isomorphic-ws: "npm:^5.0.0" - rxjs: "npm:^7.5.0" - ws: "npm:^8.14.2" - zen-observable-ts: "npm:^1.1.0" - checksum: 10/cc31fb2cd3f0940cc0d87c2acaf8da513a0255d703dc20e71d0c7f94cf4eafb4ff03980036983a9d19ca1a32cf10b2ff1ad2eb5f74b74b3bd8a297f3c6f3b3a3 - languageName: node - linkType: hard - -"@midnight-ntwrk/midnight-js-level-private-state-provider@npm:0.2.5": - version: 0.2.5 - resolution: "@midnight-ntwrk/midnight-js-level-private-state-provider@npm:0.2.5" - dependencies: - "@midnight-ntwrk/midnight-js-types": "npm:0.2.5" - abstract-level: "npm:^1.0.3" - buffer: "npm:^6.0.3" - fp-ts: "npm:^2.16.1" - io-ts: "npm:^2.2.20" - level: "npm:^8.0.0" - lodash: "npm:^4.17.21" - superjson: "npm:^1.13.1" - checksum: 10/f58dc30fc8894afde7cdf23ed25cdf2b4c7de1fe8408b3163e40a86e4dda5e2b9d40741a38194915f33216f77f98d0a9250ca78f2287e251ad44481106e57027 - languageName: node - linkType: hard - -"@midnight-ntwrk/midnight-js-network-id@npm:0.2.5": - version: 0.2.5 - resolution: "@midnight-ntwrk/midnight-js-network-id@npm:0.2.5" - checksum: 10/1cc6736f381eb2b4b368d2ac048f332dc935f4147dfa2e6065cf525ce3a43dd4cf24328117e64479007f35323904b952f9a39f28810318b630b92e6e8954b002 - languageName: node - linkType: hard - -"@midnight-ntwrk/midnight-js-node-zk-config-provider@npm:0.2.5": - version: 0.2.5 - resolution: "@midnight-ntwrk/midnight-js-node-zk-config-provider@npm:0.2.5" - dependencies: - "@midnight-ntwrk/midnight-js-types": "npm:0.2.5" - checksum: 10/b34768defa91c3aae7275644fffbd9f502fe1fa2a6b6ed8fe9620eb1a03b420becf516544137a4dd46271159aed5b25865f978c3bb92741ce77034540ae26771 - languageName: node - linkType: hard - -"@midnight-ntwrk/midnight-js-types@npm:0.2.5": - version: 0.2.5 - resolution: "@midnight-ntwrk/midnight-js-types@npm:0.2.5" - dependencies: - rxjs: "npm:^7.5.0" - checksum: 10/0c113dfe8ef8c707f2cab1e1bd9c0350c0aa31d50030b3c1a0ce00804ef1db9d5d652ba238bb4c7a5d24507e7d8c13b0d0a1ac926d55abb62c7c94a7e2083707 - languageName: node - linkType: hard - -"@midnight-ntwrk/midnight-js-utils@npm:0.2.5": - version: 0.2.5 - resolution: "@midnight-ntwrk/midnight-js-utils@npm:0.2.5" - checksum: 10/5449becaf8c39f732430b01e26fb8906281113f78441c93f9a9b17231aa9ae304da1244cea30ac36ec1bef6a597124b0ba59689b4557456ce958115538bd2a23 - languageName: node - linkType: hard - -"@midnight-ntwrk/onchain-runtime@npm:^0.2.2": +"@midnight-ntwrk/onchain-runtime@npm:^0.2.0": version: 0.2.6 resolution: "@midnight-ntwrk/onchain-runtime@npm:0.2.6" checksum: 10/6c7bf8a6d9dfd4560f1da67a0b0a2a89331eecb8110b07f7d2eab1c311cadc8f5fc42e46118649766490e534b504c0e7cad94cfdcccdbb1b09d9f69877707ebd languageName: node linkType: hard -"@midnight-ntwrk/wallet-api@npm:^3.4.2, @midnight-ntwrk/wallet-api@npm:^3.5.0": - version: 3.5.0 - resolution: "@midnight-ntwrk/wallet-api@npm:3.5.0" - dependencies: - "@midnight-ntwrk/zswap": "npm:^3.0.2" - peerDependencies: - rxjs: 7.x - checksum: 10/56777aa3d5df442767c88c4839ae397b50c09057542635a52f276999e1c831fd138bd0baf519cd339948c420e040cd49908086599fa1417f8d61123aafb514ad - languageName: node - linkType: hard - -"@midnight-ntwrk/wallet@npm:^3.7.3": - version: 3.7.5 - resolution: "@midnight-ntwrk/wallet@npm:3.7.5" - dependencies: - "@midnight-ntwrk/wallet-api": "npm:^3.5.0" - "@midnight-ntwrk/zswap": "npm:^3.0.6" - isomorphic-ws: "npm:^5.0.0" - node-fetch: "npm:3.3.2" - rxjs: "npm:^7.5" - scale-ts: "npm:^1.1.0" - ws: "npm:^8.8.1" - checksum: 10/60f57e17dc84cd980d22f6842cd82e4d1c02af20c5435833e2d8ab57559b89ac22e2fa5028f4a9d0d9da76bfcd2aa24efa2d87eef047967bbecb2c4772b9c3a0 - languageName: node - linkType: hard - -"@midnight-ntwrk/zswap@npm:^3.0.2": +"@midnight-ntwrk/zswap@npm:^3.0.6": version: 3.0.6 resolution: "@midnight-ntwrk/zswap@npm:3.0.6" checksum: 10/d095b9380d1ca9f0f94286ce31bd8aaee0ee6458d8681d5b021198c1125e9e9276ebf7bd6ca5221c800ec1d8ed27909faf866268e3673d36a5126c2c9b99b595 @@ -1046,14 +930,14 @@ __metadata: languageName: node linkType: hard -"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": +"@nodelib/fs.stat@npm:2.0.5": version: 2.0.5 resolution: "@nodelib/fs.stat@npm:2.0.5" checksum: 10/012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 languageName: node linkType: hard -"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": +"@nodelib/fs.walk@npm:^1.2.8": version: 1.2.8 resolution: "@nodelib/fs.walk@npm:1.2.8" dependencies: @@ -1085,38 +969,17 @@ __metadata: languageName: node linkType: hard -"@openzeppelin-midnight-contracts/erc20-contract@workspace:contracts/erc20/contract": - version: 0.0.0-use.local - resolution: "@openzeppelin-midnight-contracts/erc20-contract@workspace:contracts/erc20/contract" - dependencies: - "@midnight-ntwrk/compact": "workspace:*" - "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" - eslint: "npm:^8.52.0" - jest: "npm:^29.7.0" - typescript: "npm:^5.2.2" - languageName: unknown - linkType: soft - -"@openzeppelin-midnight-contracts/erc721-contract@workspace:contracts/erc721": +"@openzeppelin-midnight/erc20@workspace:contracts/erc20": version: 0.0.0-use.local - resolution: "@openzeppelin-midnight-contracts/erc721-contract@workspace:contracts/erc721" + resolution: "@openzeppelin-midnight/erc20@workspace:contracts/erc20" dependencies: - "@midnight-ntwrk/compact": "workspace:*" - "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" - eslint: "npm:^8.52.0" - jest: "npm:^29.7.0" - typescript: "npm:^5.2.2" + "@openzeppelin-midnight/utils": "workspace:^" languageName: unknown linkType: soft -"@openzeppelin-midnight-contracts/utils-contract@workspace:^, @openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils": +"@openzeppelin-midnight/utils@workspace:^, @openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local - resolution: "@openzeppelin-midnight-contracts/utils-contract@workspace:contracts/utils" - dependencies: - "@midnight-ntwrk/compact": "workspace:*" - eslint: "npm:^8.52.0" - jest: "npm:^29.7.0" - typescript: "npm:^5.2.2" + resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" languageName: unknown linkType: soft @@ -1127,34 +990,6 @@ __metadata: languageName: node linkType: hard -"@pkgr/core@npm:^0.1.0": - version: 0.1.1 - resolution: "@pkgr/core@npm:0.1.1" - checksum: 10/6f25fd2e3008f259c77207ac9915b02f1628420403b2630c92a07ff963129238c9262afc9e84344c7a23b5cc1f3965e2cd17e3798219f5fd78a63d144d3cceba - languageName: node - linkType: hard - -"@protobufjs/float@npm:^1.0.2": - version: 1.0.2 - resolution: "@protobufjs/float@npm:1.0.2" - checksum: 10/634c2c989da0ef2f4f19373d64187e2a79f598c5fb7991afb689d29a2ea17c14b796b29725945fa34b9493c17fb799e08ac0a7ccaae460ee1757d3083ed35187 - languageName: node - linkType: hard - -"@protobufjs/utf8@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/utf8@npm:1.1.0" - checksum: 10/131e289c57534c1d73a0e55782d6751dd821db1583cb2f7f7e017c9d6747addaebe79f28120b2e0185395d990aad347fb14ffa73ef4096fa38508d61a0e64602 - languageName: node - linkType: hard - -"@rtsao/scc@npm:^1.1.0": - version: 1.1.0 - resolution: "@rtsao/scc@npm:1.1.0" - checksum: 10/17d04adf404e04c1e61391ed97bca5117d4c2767a76ae3e879390d6dec7b317fcae68afbf9e98badee075d0b64fa60f287729c4942021b4d19cd01db77385c01 - languageName: node - linkType: hard - "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" @@ -1249,27 +1084,6 @@ __metadata: languageName: node linkType: hard -"@types/docker-modem@npm:*": - version: 3.0.6 - resolution: "@types/docker-modem@npm:3.0.6" - dependencies: - "@types/node": "npm:*" - "@types/ssh2": "npm:*" - checksum: 10/cc58e8189f6ec5a2b8ca890207402178a97ddac8c80d125dc65d8ab29034b5db736de15e99b91b2d74e66d14e26e73b6b8b33216613dd15fd3aa6b82c11a83ed - languageName: node - linkType: hard - -"@types/dockerode@npm:^3.3.29": - version: 3.3.35 - resolution: "@types/dockerode@npm:3.3.35" - dependencies: - "@types/docker-modem": "npm:*" - "@types/node": "npm:*" - "@types/ssh2": "npm:*" - checksum: 10/9b1bc6ffc032c5fd76564c4b2c80724eddcba4c0deb885105b811f0a843464f3152e44ea850d91b614f234e35fa70002aa7350d109517460a7fc339800833ade - languageName: node - linkType: hard - "@types/graceful-fs@npm:^4.1.3": version: 4.1.9 resolution: "@types/graceful-fs@npm:4.1.9" @@ -1314,20 +1128,6 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:^7.0.12": - version: 7.0.15 - resolution: "@types/json-schema@npm:7.0.15" - checksum: 10/1a3c3e06236e4c4aab89499c428d585527ce50c24fe8259e8b3926d3df4cfbbbcf306cfc73ddfb66cbafc973116efd15967020b0f738f63e09e64c7d260519e7 - languageName: node - linkType: hard - -"@types/json5@npm:^0.0.29": - version: 0.0.29 - resolution: "@types/json5@npm:0.0.29" - checksum: 10/4e5aed58cabb2bbf6f725da13421aa50a49abb6bc17bfab6c31b8774b073fa7b50d557c61f961a09a85f6056151190f8ac95f13f5b48136ba5841f7d4484ec56 - languageName: node - linkType: hard - "@types/node@npm:*": version: 22.13.8 resolution: "@types/node@npm:22.13.8" @@ -1337,7 +1137,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^18.11.18, @types/node@npm:^18.18.6": +"@types/node@npm:^18.18.6": version: 18.19.78 resolution: "@types/node@npm:18.19.78" dependencies: @@ -1353,41 +1153,6 @@ __metadata: languageName: node linkType: hard -"@types/semver@npm:^7.5.0": - version: 7.5.8 - resolution: "@types/semver@npm:7.5.8" - checksum: 10/3496808818ddb36deabfe4974fd343a78101fa242c4690044ccdc3b95dcf8785b494f5d628f2f47f38a702f8db9c53c67f47d7818f2be1b79f2efb09692e1178 - languageName: node - linkType: hard - -"@types/ssh2-streams@npm:*": - version: 0.1.12 - resolution: "@types/ssh2-streams@npm:0.1.12" - dependencies: - "@types/node": "npm:*" - checksum: 10/377bfff70e6c13e42f7bf832209c916b9a80491bba611c21f4cbdc8c9f99553794e5583ee933fd02bb1b056dd9b97433195452f119104f592a5a2440806f3087 - languageName: node - linkType: hard - -"@types/ssh2@npm:*": - version: 1.15.4 - resolution: "@types/ssh2@npm:1.15.4" - dependencies: - "@types/node": "npm:^18.11.18" - checksum: 10/a4d37e28bf81c6bc41c785d78ee0208163af86294411f9662097f72bf91bb14647d4786f7a01a5c8e74594cfc1ccedcf9495bfdfb5541f2262a2cf433c94c5d9 - languageName: node - linkType: hard - -"@types/ssh2@npm:^0.5.48": - version: 0.5.52 - resolution: "@types/ssh2@npm:0.5.52" - dependencies: - "@types/node": "npm:*" - "@types/ssh2-streams": "npm:*" - checksum: 10/fc2584af091da49da9d6628dd8a5e851b217bb9b1b732b0361903894f2730ab3fdf8634f954be34c5a513f7eb0b2772d059d64062bcf6b4a0eb73bfc83c4b858 - languageName: node - linkType: hard - "@types/stack-utils@npm:^2.0.0": version: 2.0.3 resolution: "@types/stack-utils@npm:2.0.3" @@ -1411,262 +1176,79 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^6.8.0": - version: 6.21.0 - resolution: "@typescript-eslint/eslint-plugin@npm:6.21.0" - dependencies: - "@eslint-community/regexpp": "npm:^4.5.1" - "@typescript-eslint/scope-manager": "npm:6.21.0" - "@typescript-eslint/type-utils": "npm:6.21.0" - "@typescript-eslint/utils": "npm:6.21.0" - "@typescript-eslint/visitor-keys": "npm:6.21.0" - debug: "npm:^4.3.4" - graphemer: "npm:^1.4.0" - ignore: "npm:^5.2.4" - natural-compare: "npm:^1.4.0" - semver: "npm:^7.5.4" - ts-api-utils: "npm:^1.0.1" - peerDependencies: - "@typescript-eslint/parser": ^6.0.0 || ^6.0.0-alpha - eslint: ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10/a57de0f630789330204cc1531f86cfc68b391cafb1ba67c8992133f1baa2a09d629df66e71260b040de4c9a3ff1252952037093c4128b0d56c4dbb37720b4c1d +"@ungap/structured-clone@npm:^1.2.0": + version: 1.3.0 + resolution: "@ungap/structured-clone@npm:1.3.0" + checksum: 10/80d6910946f2b1552a2406650051c91bbd1f24a6bf854354203d84fe2714b3e8ce4618f49cc3410494173a1c1e8e9777372fe68dce74bd45faf0a7a1a6ccf448 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^6.8.0": - version: 6.21.0 - resolution: "@typescript-eslint/parser@npm:6.21.0" - dependencies: - "@typescript-eslint/scope-manager": "npm:6.21.0" - "@typescript-eslint/types": "npm:6.21.0" - "@typescript-eslint/typescript-estree": "npm:6.21.0" - "@typescript-eslint/visitor-keys": "npm:6.21.0" - debug: "npm:^4.3.4" +"abbrev@npm:^3.0.0": + version: 3.0.0 + resolution: "abbrev@npm:3.0.0" + checksum: 10/2ceee14efdeda42ef7355178c1069499f183546ff7112b3efe79c1edef09d20ad9c17939752215fb8f7fcf48d10e6a7c0aa00136dc9cf4d293d963718bb1d200 + languageName: node + linkType: hard + +"acorn-jsx@npm:^5.3.2": + version: 5.3.2 + resolution: "acorn-jsx@npm:5.3.2" peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10/4d51cdbc170e72275efc5ef5fce48a81ec431e4edde8374f4d0213d8d370a06823e1a61ae31d502a5f1b0d1f48fc4d29a1b1b5c2dcf809d66d3872ccf6e46ac7 + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10/d4371eaef7995530b5b5ca4183ff6f062ca17901a6d3f673c9ac011b01ede37e7a1f7f61f8f5cfe709e88054757bb8f3277dc4061087cdf4f2a1f90ccbcdb977 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.21.0": - version: 6.21.0 - resolution: "@typescript-eslint/scope-manager@npm:6.21.0" +"acorn-walk@npm:^8.1.1": + version: 8.3.4 + resolution: "acorn-walk@npm:8.3.4" dependencies: - "@typescript-eslint/types": "npm:6.21.0" - "@typescript-eslint/visitor-keys": "npm:6.21.0" - checksum: 10/fe91ac52ca8e09356a71dc1a2f2c326480f3cccfec6b2b6d9154c1a90651ab8ea270b07c67df5678956c3bbf0bbe7113ab68f68f21b20912ea528b1214197395 + acorn: "npm:^8.11.0" + checksum: 10/871386764e1451c637bb8ab9f76f4995d408057e9909be6fb5ad68537ae3375d85e6a6f170b98989f44ab3ff6c74ad120bc2779a3d577606e7a0cd2b4efcaf77 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:6.21.0": - version: 6.21.0 - resolution: "@typescript-eslint/type-utils@npm:6.21.0" - dependencies: - "@typescript-eslint/typescript-estree": "npm:6.21.0" - "@typescript-eslint/utils": "npm:6.21.0" - debug: "npm:^4.3.4" - ts-api-utils: "npm:^1.0.1" - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10/d03fb3ee1caa71f3ce053505f1866268d7ed79ffb7fed18623f4a1253f5b8f2ffc92636d6fd08fcbaf5bd265a6de77bf192c53105131e4724643dfc910d705fc +"acorn@npm:^8.11.0, acorn@npm:^8.4.1, acorn@npm:^8.9.0": + version: 8.14.0 + resolution: "acorn@npm:8.14.0" + bin: + acorn: bin/acorn + checksum: 10/6df29c35556782ca9e632db461a7f97947772c6c1d5438a81f0c873a3da3a792487e83e404d1c6c25f70513e91aa18745f6eafb1fcc3a43ecd1920b21dd173d2 languageName: node linkType: hard -"@typescript-eslint/types@npm:6.21.0": - version: 6.21.0 - resolution: "@typescript-eslint/types@npm:6.21.0" - checksum: 10/e26da86d6f36ca5b6ef6322619f8ec55aabcd7d43c840c977ae13ae2c964c3091fc92eb33730d8be08927c9de38466c5323e78bfb270a9ff1d3611fe821046c5 +"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": + version: 7.1.3 + resolution: "agent-base@npm:7.1.3" + checksum: 10/3db6d8d4651f2aa1a9e4af35b96ab11a7607af57a24f3bc721a387eaa3b5f674e901f0a648b0caefd48f3fd117c7761b79a3b55854e2aebaa96c3f32cf76af84 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.21.0": - version: 6.21.0 - resolution: "@typescript-eslint/typescript-estree@npm:6.21.0" +"ajv@npm:^6.12.4": + version: 6.12.6 + resolution: "ajv@npm:6.12.6" dependencies: - "@typescript-eslint/types": "npm:6.21.0" - "@typescript-eslint/visitor-keys": "npm:6.21.0" - debug: "npm:^4.3.4" - globby: "npm:^11.1.0" - is-glob: "npm:^4.0.3" - minimatch: "npm:9.0.3" - semver: "npm:^7.5.4" - ts-api-utils: "npm:^1.0.1" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10/b32fa35fca2a229e0f5f06793e5359ff9269f63e9705e858df95d55ca2cd7fdb5b3e75b284095a992c48c5fc46a1431a1a4b6747ede2dd08929dc1cbacc589b8 + fast-deep-equal: "npm:^3.1.1" + fast-json-stable-stringify: "npm:^2.0.0" + json-schema-traverse: "npm:^0.4.1" + uri-js: "npm:^4.2.2" + checksum: 10/48d6ad21138d12eb4d16d878d630079a2bda25a04e745c07846a4ad768319533031e28872a9b3c5790fa1ec41aabdf2abed30a56e5a03ebc2cf92184b8ee306c languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.21.0": - version: 6.21.0 - resolution: "@typescript-eslint/utils@npm:6.21.0" +"ansi-escapes@npm:^4.2.1": + version: 4.3.2 + resolution: "ansi-escapes@npm:4.3.2" dependencies: - "@eslint-community/eslint-utils": "npm:^4.4.0" - "@types/json-schema": "npm:^7.0.12" - "@types/semver": "npm:^7.5.0" - "@typescript-eslint/scope-manager": "npm:6.21.0" - "@typescript-eslint/types": "npm:6.21.0" - "@typescript-eslint/typescript-estree": "npm:6.21.0" - semver: "npm:^7.5.4" - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - checksum: 10/b404a2c55a425a79d054346ae123087d30c7ecf7ed7abcf680c47bf70c1de4fabadc63434f3f460b2fa63df76bc9e4a0b9fa2383bb8a9fcd62733fb5c4e4f3e3 + type-fest: "npm:^0.21.3" + checksum: 10/8661034456193ffeda0c15c8c564a9636b0c04094b7f78bd01517929c17c504090a60f7a75f949f5af91289c264d3e1001d91492c1bd58efc8e100500ce04de2 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.21.0": - version: 6.21.0 - resolution: "@typescript-eslint/visitor-keys@npm:6.21.0" - dependencies: - "@typescript-eslint/types": "npm:6.21.0" - eslint-visitor-keys: "npm:^3.4.1" - checksum: 10/30422cdc1e2ffad203df40351a031254b272f9c6f2b7e02e9bfa39e3fc2c7b1c6130333b0057412968deda17a3a68a578a78929a8139c6acef44d9d841dc72e1 - languageName: node - linkType: hard - -"@ungap/structured-clone@npm:^1.2.0": - version: 1.3.0 - resolution: "@ungap/structured-clone@npm:1.3.0" - checksum: 10/80d6910946f2b1552a2406650051c91bbd1f24a6bf854354203d84fe2714b3e8ce4618f49cc3410494173a1c1e8e9777372fe68dce74bd45faf0a7a1a6ccf448 - languageName: node - linkType: hard - -"@wry/caches@npm:^1.0.0": - version: 1.0.1 - resolution: "@wry/caches@npm:1.0.1" - dependencies: - tslib: "npm:^2.3.0" - checksum: 10/055f592ee52b5fd9aa86e274e54e4a8b2650f619000bf6f61880ce14aaf47eb2ab34f3ada2eab964fe8b2f19bf8097ecacddcea4638fcc64c3d3a0a512aaa07c - languageName: node - linkType: hard - -"@wry/context@npm:^0.7.0": - version: 0.7.4 - resolution: "@wry/context@npm:0.7.4" - dependencies: - tslib: "npm:^2.3.0" - checksum: 10/70d648949a97a035b2be2d6ddb716d4162113e850ab2c4c86331b2da94a7e826204080ce04eee2a95665bd3a0b245bf2ea3aae9adfa57b004ae0d2d49bdb5c8f - languageName: node - linkType: hard - -"@wry/equality@npm:^0.5.6": - version: 0.5.7 - resolution: "@wry/equality@npm:0.5.7" - dependencies: - tslib: "npm:^2.3.0" - checksum: 10/69dccf33c0c41fd7ec5550f5703b857c6484a949412ad747001da941270ea436648c3ab988a2091765304249585ac30c7b417fad8be9a7ce19c1221f71548e35 - languageName: node - linkType: hard - -"@wry/trie@npm:^0.5.0": - version: 0.5.0 - resolution: "@wry/trie@npm:0.5.0" - dependencies: - tslib: "npm:^2.3.0" - checksum: 10/578a08f3a96256c9b163230337183d9511fd775bdfe147a30561ccaacedc9ce33b9731ee6e591bb1f5f53e41b26789e519b47dff5100c7bf4e1cd2df3062f797 - languageName: node - linkType: hard - -"abbrev@npm:^3.0.0": - version: 3.0.0 - resolution: "abbrev@npm:3.0.0" - checksum: 10/2ceee14efdeda42ef7355178c1069499f183546ff7112b3efe79c1edef09d20ad9c17939752215fb8f7fcf48d10e6a7c0aa00136dc9cf4d293d963718bb1d200 - languageName: node - linkType: hard - -"abort-controller@npm:^3.0.0": - version: 3.0.0 - resolution: "abort-controller@npm:3.0.0" - dependencies: - event-target-shim: "npm:^5.0.0" - checksum: 10/ed84af329f1828327798229578b4fe03a4dd2596ba304083ebd2252666bdc1d7647d66d0b18704477e1f8aa315f055944aa6e859afebd341f12d0a53c37b4b40 - languageName: node - linkType: hard - -"abstract-level@npm:^1.0.2, abstract-level@npm:^1.0.3, abstract-level@npm:^1.0.4": - version: 1.0.4 - resolution: "abstract-level@npm:1.0.4" - dependencies: - buffer: "npm:^6.0.3" - catering: "npm:^2.1.0" - is-buffer: "npm:^2.0.5" - level-supports: "npm:^4.0.0" - level-transcoder: "npm:^1.0.1" - module-error: "npm:^1.0.1" - queue-microtask: "npm:^1.2.3" - checksum: 10/8edf4cf55b7b66b653296f53a643bcf1501074be099d8c44351595cd33f769b7b2aed216d5fffe1c99ebea4acf14f5ae093e98baa60ea1d236ea8a3387350ebb - languageName: node - linkType: hard - -"acorn-jsx@npm:^5.3.2": - version: 5.3.2 - resolution: "acorn-jsx@npm:5.3.2" - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 10/d4371eaef7995530b5b5ca4183ff6f062ca17901a6d3f673c9ac011b01ede37e7a1f7f61f8f5cfe709e88054757bb8f3277dc4061087cdf4f2a1f90ccbcdb977 - languageName: node - linkType: hard - -"acorn-walk@npm:^8.1.1": - version: 8.3.4 - resolution: "acorn-walk@npm:8.3.4" - dependencies: - acorn: "npm:^8.11.0" - checksum: 10/871386764e1451c637bb8ab9f76f4995d408057e9909be6fb5ad68537ae3375d85e6a6f170b98989f44ab3ff6c74ad120bc2779a3d577606e7a0cd2b4efcaf77 - languageName: node - linkType: hard - -"acorn@npm:^8.11.0, acorn@npm:^8.4.1, acorn@npm:^8.9.0": - version: 8.14.0 - resolution: "acorn@npm:8.14.0" - bin: - acorn: bin/acorn - checksum: 10/6df29c35556782ca9e632db461a7f97947772c6c1d5438a81f0c873a3da3a792487e83e404d1c6c25f70513e91aa18745f6eafb1fcc3a43ecd1920b21dd173d2 - languageName: node - linkType: hard - -"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": - version: 7.1.3 - resolution: "agent-base@npm:7.1.3" - checksum: 10/3db6d8d4651f2aa1a9e4af35b96ab11a7607af57a24f3bc721a387eaa3b5f674e901f0a648b0caefd48f3fd117c7761b79a3b55854e2aebaa96c3f32cf76af84 - languageName: node - linkType: hard - -"ajv@npm:^6.12.4": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" - dependencies: - fast-deep-equal: "npm:^3.1.1" - fast-json-stable-stringify: "npm:^2.0.0" - json-schema-traverse: "npm:^0.4.1" - uri-js: "npm:^4.2.2" - checksum: 10/48d6ad21138d12eb4d16d878d630079a2bda25a04e745c07846a4ad768319533031e28872a9b3c5790fa1ec41aabdf2abed30a56e5a03ebc2cf92184b8ee306c - languageName: node - linkType: hard - -"ansi-escapes@npm:^4.2.1": - version: 4.3.2 - resolution: "ansi-escapes@npm:4.3.2" - dependencies: - type-fest: "npm:^0.21.3" - checksum: 10/8661034456193ffeda0c15c8c564a9636b0c04094b7f78bd01517929c17c504090a60f7a75f949f5af91289c264d3e1001d91492c1bd58efc8e100500ce04de2 - languageName: node - linkType: hard - -"ansi-regex@npm:^5.0.1": - version: 5.0.1 - resolution: "ansi-regex@npm:5.0.1" - checksum: 10/2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b +"ansi-regex@npm:^5.0.1": + version: 5.0.1 + resolution: "ansi-regex@npm:5.0.1" + checksum: 10/2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b languageName: node linkType: hard @@ -1710,36 +1292,6 @@ __metadata: languageName: node linkType: hard -"archiver-utils@npm:^5.0.0, archiver-utils@npm:^5.0.2": - version: 5.0.2 - resolution: "archiver-utils@npm:5.0.2" - dependencies: - glob: "npm:^10.0.0" - graceful-fs: "npm:^4.2.0" - is-stream: "npm:^2.0.1" - lazystream: "npm:^1.0.0" - lodash: "npm:^4.17.15" - normalize-path: "npm:^3.0.0" - readable-stream: "npm:^4.0.0" - checksum: 10/9dde4aa3f0cb1bdfe0b3d4c969f82e6cca9ae76338b7fee6f0071a14a2a38c0cdd1c41ecd3e362466585aa6cc5d07e9e435abea8c94fd9c7ace35f184abef9e4 - languageName: node - linkType: hard - -"archiver@npm:^7.0.1": - version: 7.0.1 - resolution: "archiver@npm:7.0.1" - dependencies: - archiver-utils: "npm:^5.0.2" - async: "npm:^3.2.4" - buffer-crc32: "npm:^1.0.0" - readable-stream: "npm:^4.0.0" - readdir-glob: "npm:^1.1.2" - tar-stream: "npm:^3.0.0" - zip-stream: "npm:^6.0.1" - checksum: 10/81c6102db99d7ffd5cb2aed02a678f551c6603991a059ca66ef59249942b835a651a3d3b5240af4f8bec4e61e13790357c9d1ad4a99982bd2cc4149575c31d67 - languageName: node - linkType: hard - "arg@npm:^4.1.0": version: 4.1.3 resolution: "arg@npm:4.1.3" @@ -1763,143 +1315,13 @@ __metadata: languageName: node linkType: hard -"array-buffer-byte-length@npm:^1.0.1, array-buffer-byte-length@npm:^1.0.2": - version: 1.0.2 - resolution: "array-buffer-byte-length@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.3" - is-array-buffer: "npm:^3.0.5" - checksum: 10/0ae3786195c3211b423e5be8dd93357870e6fb66357d81da968c2c39ef43583ef6eece1f9cb1caccdae4806739c65dea832b44b8593414313cd76a89795fca63 - languageName: node - linkType: hard - -"array-includes@npm:^3.1.8": - version: 3.1.8 - resolution: "array-includes@npm:3.1.8" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - es-object-atoms: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.4" - is-string: "npm:^1.0.7" - checksum: 10/290b206c9451f181fb2b1f79a3bf1c0b66bb259791290ffbada760c79b284eef6f5ae2aeb4bcff450ebc9690edd25732c4c73a3c2b340fcc0f4563aed83bf488 - languageName: node - linkType: hard - -"array-union@npm:^2.1.0": - version: 2.1.0 - resolution: "array-union@npm:2.1.0" - checksum: 10/5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d - languageName: node - linkType: hard - -"array.prototype.findlastindex@npm:^1.2.5": - version: 1.2.5 - resolution: "array.prototype.findlastindex@npm:1.2.5" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10/7c5c821f357cd53ab6cc305de8086430dd8d7a2485db87b13f843e868055e9582b1fd338f02338f67fc3a1603ceaf9610dd2a470b0b506f9d18934780f95b246 - languageName: node - linkType: hard - -"array.prototype.flat@npm:^1.3.2": - version: 1.3.3 - resolution: "array.prototype.flat@npm:1.3.3" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10/f9b992fa0775d8f7c97abc91eb7f7b2f0ed8430dd9aeb9fdc2967ac4760cdd7fc2ef7ead6528fef40c7261e4d790e117808ce0d3e7e89e91514d4963a531cd01 - languageName: node - linkType: hard - -"array.prototype.flatmap@npm:^1.3.2": - version: 1.3.3 - resolution: "array.prototype.flatmap@npm:1.3.3" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10/473534573aa4b37b1d80705d0ce642f5933cccf5617c9f3e8a56686e9815ba93d469138e86a1f25d2fe8af999c3d24f54d703ec1fc2db2e6778d46d0f4ac951e - languageName: node - linkType: hard - -"arraybuffer.prototype.slice@npm:^1.0.4": - version: 1.0.4 - resolution: "arraybuffer.prototype.slice@npm:1.0.4" - dependencies: - array-buffer-byte-length: "npm:^1.0.1" - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - is-array-buffer: "npm:^3.0.4" - checksum: 10/4821ebdfe7d699f910c7f09bc9fa996f09b96b80bccb4f5dd4b59deae582f6ad6e505ecef6376f8beac1eda06df2dbc89b70e82835d104d6fcabd33c1aed1ae9 - languageName: node - linkType: hard - -"asn1@npm:^0.2.6": - version: 0.2.6 - resolution: "asn1@npm:0.2.6" - dependencies: - safer-buffer: "npm:~2.1.0" - checksum: 10/cf629291fee6c1a6f530549939433ebf32200d7849f38b810ff26ee74235e845c0c12b2ed0f1607ac17383d19b219b69cefa009b920dab57924c5c544e495078 - languageName: node - linkType: hard - -"async-function@npm:^1.0.0": - version: 1.0.0 - resolution: "async-function@npm:1.0.0" - checksum: 10/1a09379937d846f0ce7614e75071c12826945d4e417db634156bf0e4673c495989302f52186dfa9767a1d9181794554717badd193ca2bbab046ef1da741d8efd - languageName: node - linkType: hard - -"async-lock@npm:^1.4.1": - version: 1.4.1 - resolution: "async-lock@npm:1.4.1" - checksum: 10/80d55ac95f920e880a865968b799963014f6d987dd790dd08173fae6e1af509d8cd0ab45a25daaca82e3ef8e7c939f5d128cd1facfcc5c647da8ac2409e20ef9 - languageName: node - linkType: hard - -"async@npm:^3.2.3, async@npm:^3.2.4": +"async@npm:^3.2.3": version: 3.2.6 resolution: "async@npm:3.2.6" checksum: 10/cb6e0561a3c01c4b56a799cc8bab6ea5fef45f069ab32500b6e19508db270ef2dffa55e5aed5865c5526e9907b1f8be61b27530823b411ffafb5e1538c86c368 languageName: node linkType: hard -"atomic-sleep@npm:^1.0.0": - version: 1.0.0 - resolution: "atomic-sleep@npm:1.0.0" - checksum: 10/3ab6d2cf46b31394b4607e935ec5c1c3c4f60f3e30f0913d35ea74b51b3585e84f590d09e58067f11762eec71c87d25314ce859030983dc0e4397eed21daa12e - languageName: node - linkType: hard - -"available-typed-arrays@npm:^1.0.7": - version: 1.0.7 - resolution: "available-typed-arrays@npm:1.0.7" - dependencies: - possible-typed-array-names: "npm:^1.0.0" - checksum: 10/6c9da3a66caddd83c875010a1ca8ef11eac02ba15fb592dc9418b2b5e7b77b645fa7729380a92d9835c2f05f2ca1b6251f39b993e0feb3f1517c74fa1af02cab - languageName: node - linkType: hard - -"b4a@npm:^1.6.4": - version: 1.6.7 - resolution: "b4a@npm:1.6.7" - checksum: 10/1ac056e3bce378d4d3e570e57319360a9d3125ab6916a1921b95bea33d9ee646698ebc75467561fd6fcc80ff697612124c89bb9b95e80db94c6dc23fcb977705 - languageName: node - linkType: hard - "babel-jest@npm:^29.7.0": version: 29.7.0 resolution: "babel-jest@npm:29.7.0" @@ -1986,84 +1408,6 @@ __metadata: languageName: node linkType: hard -"bare-events@npm:^2.0.0, bare-events@npm:^2.2.0": - version: 2.5.4 - resolution: "bare-events@npm:2.5.4" - checksum: 10/135ef380b13f554ca2c6905bdbcfac8edae08fce85b7f953fa01f09a9f5b0da6a25e414111659bc9a6118216f0dd1f732016acd11ce91517f2afb26ebeb4b721 - languageName: node - linkType: hard - -"bare-fs@npm:^4.0.1": - version: 4.0.1 - resolution: "bare-fs@npm:4.0.1" - dependencies: - bare-events: "npm:^2.0.0" - bare-path: "npm:^3.0.0" - bare-stream: "npm:^2.0.0" - checksum: 10/70951cf7d7522f0b6780bdfaf7969226db85370fa107b1eee71c58272573463388b40203595a8826cd55ca34e6359ca4b1ee91fd5d0b8ea64ab0d1f9979de262 - languageName: node - linkType: hard - -"bare-os@npm:^3.0.1": - version: 3.5.1 - resolution: "bare-os@npm:3.5.1" - checksum: 10/ff65328cb83bf8ed1f527f1bf46ec0a9990d76575bc3ab464f0299f9e94fea551af7c044c1471967fc220be5f0ddd420e8580bc4e7a1be9a1a16bf944b45f89e - languageName: node - linkType: hard - -"bare-path@npm:^3.0.0": - version: 3.0.0 - resolution: "bare-path@npm:3.0.0" - dependencies: - bare-os: "npm:^3.0.1" - checksum: 10/712d90e9cd8c3263cc11b0e0d386d1531a452706d7840c081ee586b34b00d72544e65df7a40013d47c1b177277495225deeede65cb2984db88a979cb65aaa2ff - languageName: node - linkType: hard - -"bare-stream@npm:^2.0.0": - version: 2.6.5 - resolution: "bare-stream@npm:2.6.5" - dependencies: - streamx: "npm:^2.21.0" - peerDependencies: - bare-buffer: "*" - bare-events: "*" - peerDependenciesMeta: - bare-buffer: - optional: true - bare-events: - optional: true - checksum: 10/0f5ca2167fbbccc118157bce7c53a933e21726268e03d751461211550d72b2d01c296b767ccf96aae8ab28e106b126407c6fe0d29f915734b844ffe6057f0a08 - languageName: node - linkType: hard - -"base64-js@npm:^1.3.1": - version: 1.5.1 - resolution: "base64-js@npm:1.5.1" - checksum: 10/669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 - languageName: node - linkType: hard - -"bcrypt-pbkdf@npm:^1.0.2": - version: 1.0.2 - resolution: "bcrypt-pbkdf@npm:1.0.2" - dependencies: - tweetnacl: "npm:^0.14.3" - checksum: 10/13a4cde058250dbf1fa77a4f1b9a07d32ae2e3b9e28e88a0c7a1827835bc3482f3e478c4a0cfd4da6ff0c46dae07da1061123a995372b32cc563d9975f975404 - languageName: node - linkType: hard - -"bl@npm:^4.0.3": - version: 4.1.0 - resolution: "bl@npm:4.1.0" - dependencies: - buffer: "npm:^5.5.0" - inherits: "npm:^2.0.4" - readable-stream: "npm:^3.4.0" - checksum: 10/b7904e66ed0bdfc813c06ea6c3e35eafecb104369dbf5356d0f416af90c1546de3b74e5b63506f0629acf5e16a6f87c3798f16233dcff086e9129383aa02ab55 - languageName: node - linkType: hard - "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" @@ -2092,18 +1436,6 @@ __metadata: languageName: node linkType: hard -"browser-level@npm:^1.0.1": - version: 1.0.1 - resolution: "browser-level@npm:1.0.1" - dependencies: - abstract-level: "npm:^1.0.2" - catering: "npm:^2.1.1" - module-error: "npm:^1.0.2" - run-parallel-limit: "npm:^1.1.0" - checksum: 10/e712569111782da76853fecf648b43ff878ff2301c2830a9e7399685b646824a85f304dea5f023e02ee41a63a972f9aad734bd411069095adc9c79784fc649a5 - languageName: node - linkType: hard - "browserslist@npm:^4.24.0": version: 4.24.4 resolution: "browserslist@npm:4.24.4" @@ -2136,13 +1468,6 @@ __metadata: languageName: node linkType: hard -"buffer-crc32@npm:^1.0.0": - version: 1.0.0 - resolution: "buffer-crc32@npm:1.0.0" - checksum: 10/ef3b7c07622435085c04300c9a51e850ec34a27b2445f758eef69b859c7827848c2282f3840ca6c1eef3829145a1580ce540cab03ccf4433827a2b95d3b09ca7 - languageName: node - linkType: hard - "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" @@ -2150,56 +1475,6 @@ __metadata: languageName: node linkType: hard -"buffer@npm:^5.5.0": - version: 5.7.1 - resolution: "buffer@npm:5.7.1" - dependencies: - base64-js: "npm:^1.3.1" - ieee754: "npm:^1.1.13" - checksum: 10/997434d3c6e3b39e0be479a80288875f71cd1c07d75a3855e6f08ef848a3c966023f79534e22e415ff3a5112708ce06127277ab20e527146d55c84566405c7c6 - languageName: node - linkType: hard - -"buffer@npm:^6.0.3": - version: 6.0.3 - resolution: "buffer@npm:6.0.3" - dependencies: - base64-js: "npm:^1.3.1" - ieee754: "npm:^1.2.1" - checksum: 10/b6bc68237ebf29bdacae48ce60e5e28fc53ae886301f2ad9496618efac49427ed79096750033e7eab1897a4f26ae374ace49106a5758f38fb70c78c9fda2c3b1 - languageName: node - linkType: hard - -"buildcheck@npm:~0.0.6": - version: 0.0.6 - resolution: "buildcheck@npm:0.0.6" - checksum: 10/194ee8d3b0926fd6f3e799732130ad7ab194882c56900b8670ad43c81326f64871f49b7d9f1e9baad91ca3070eb4e8b678797fe9ae78cf87dde86d8916eb25d2 - languageName: node - linkType: hard - -"builtin-modules@npm:^3.3.0": - version: 3.3.0 - resolution: "builtin-modules@npm:3.3.0" - checksum: 10/62e063ab40c0c1efccbfa9ffa31873e4f9d57408cb396a2649981a0ecbce56aabc93c28feaccbc5658c95aab2703ad1d11980e62ec2e5e72637404e1eb60f39e - languageName: node - linkType: hard - -"builtins@npm:^5.0.1": - version: 5.1.0 - resolution: "builtins@npm:5.1.0" - dependencies: - semver: "npm:^7.0.0" - checksum: 10/60aa9969f69656bf6eab82cd74b23ab805f112ae46a54b912bccc1533875760f2d2ce95e0a7d13144e35ada9f0386f17ed4961908bc9434b5a5e21375b1902b2 - languageName: node - linkType: hard - -"byline@npm:^5.0.0": - version: 5.0.0 - resolution: "byline@npm:5.0.0" - checksum: 10/737ca83e8eda2976728dae62e68bc733aea095fab08db4c6f12d3cee3cf45b6f97dce45d1f6b6ff9c2c947736d10074985b4425b31ce04afa1985a4ef3d334a7 - languageName: node - linkType: hard - "cacache@npm:^19.0.1": version: 19.0.1 resolution: "cacache@npm:19.0.1" @@ -2220,38 +1495,6 @@ __metadata: languageName: node linkType: hard -"call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": - version: 1.0.2 - resolution: "call-bind-apply-helpers@npm:1.0.2" - dependencies: - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - checksum: 10/00482c1f6aa7cfb30fb1dbeb13873edf81cfac7c29ed67a5957d60635a56b2a4a480f1016ddbdb3395cc37900d46037fb965043a51c5c789ffeab4fc535d18b5 - languageName: node - linkType: hard - -"call-bind@npm:^1.0.7, call-bind@npm:^1.0.8": - version: 1.0.8 - resolution: "call-bind@npm:1.0.8" - dependencies: - call-bind-apply-helpers: "npm:^1.0.0" - es-define-property: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.4" - set-function-length: "npm:^1.2.2" - checksum: 10/659b03c79bbfccf0cde3a79e7d52570724d7290209823e1ca5088f94b52192dc1836b82a324d0144612f816abb2f1734447438e38d9dafe0b3f82c2a1b9e3bce - languageName: node - linkType: hard - -"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3": - version: 1.0.3 - resolution: "call-bound@npm:1.0.3" - dependencies: - call-bind-apply-helpers: "npm:^1.0.1" - get-intrinsic: "npm:^1.2.6" - checksum: 10/c39a8245f68cdb7c1f5eea7b3b1e3a7a90084ea6efebb78ebc454d698ade2c2bb42ec033abc35f1e596d62496b6100e9f4cdfad1956476c510130e2cda03266d - languageName: node - linkType: hard - "callsites@npm:^3.0.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" @@ -2280,13 +1523,6 @@ __metadata: languageName: node linkType: hard -"catering@npm:^2.1.0, catering@npm:^2.1.1": - version: 2.1.1 - resolution: "catering@npm:2.1.1" - checksum: 10/4669c9fa5f3a73273535fb458a964d8aba12dc5102d8487049cf03623bef3cdff4b5d9f92ff04c00f1001057a7cc7df6e700752ac622c2a7baf7bcff34166683 - languageName: node - linkType: hard - "chalk@npm:^4.0.0, chalk@npm:^4.0.2": version: 4.1.2 resolution: "chalk@npm:4.1.2" @@ -2304,13 +1540,6 @@ __metadata: languageName: node linkType: hard -"chownr@npm:^1.1.1": - version: 1.1.4 - resolution: "chownr@npm:1.1.4" - checksum: 10/115648f8eb38bac5e41c3857f3e663f9c39ed6480d1349977c4d96c95a47266fcacc5a5aabf3cb6c481e22d72f41992827db47301851766c4fd77ac21a4f081d - languageName: node - linkType: hard - "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -2332,20 +1561,6 @@ __metadata: languageName: node linkType: hard -"classic-level@npm:^1.2.0": - version: 1.4.1 - resolution: "classic-level@npm:1.4.1" - dependencies: - abstract-level: "npm:^1.0.2" - catering: "npm:^2.1.0" - module-error: "npm:^1.0.1" - napi-macros: "npm:^2.2.2" - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.3.0" - checksum: 10/11f9362301477cb5cf3b147e5846754e0e4296231e265145101403f4a5cb797a685b6a9b6b4c880a42b05772f846a222a5a7a563262ca15b5ca03e25e9a805db - languageName: node - linkType: hard - "cliui@npm:^8.0.1": version: 8.0.1 resolution: "cliui@npm:8.0.1" @@ -2387,26 +1602,6 @@ __metadata: languageName: node linkType: hard -"colorette@npm:^2.0.7": - version: 2.0.20 - resolution: "colorette@npm:2.0.20" - checksum: 10/0b8de48bfa5d10afc160b8eaa2b9938f34a892530b2f7d7897e0458d9535a066e3998b49da9d21161c78225b272df19ae3a64d6df28b4c9734c0e55bbd02406f - languageName: node - linkType: hard - -"compress-commons@npm:^6.0.2": - version: 6.0.2 - resolution: "compress-commons@npm:6.0.2" - dependencies: - crc-32: "npm:^1.2.0" - crc32-stream: "npm:^6.0.0" - is-stream: "npm:^2.0.1" - normalize-path: "npm:^3.0.0" - readable-stream: "npm:^4.0.0" - checksum: 10/78e3ba10aeef919a1c5bbac21e120f3e1558a31b2defebbfa1635274fc7f7e8a3a0ee748a06249589acd0b33a0d58144b8238ff77afc3220f8d403a96fcc13aa - languageName: node - linkType: hard - "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -2421,52 +1616,6 @@ __metadata: languageName: node linkType: hard -"copy-anything@npm:^3.0.2": - version: 3.0.5 - resolution: "copy-anything@npm:3.0.5" - dependencies: - is-what: "npm:^4.1.8" - checksum: 10/4c41385a94a1cff6352a954f9b1c05b6bb1b70713a2d31f4c7b188ae7187ce00ddcc9c09bd58d24cd35b67fc6dd84df5954c0be86ea10700ff74e677db3cb09c - languageName: node - linkType: hard - -"core-util-is@npm:~1.0.0": - version: 1.0.3 - resolution: "core-util-is@npm:1.0.3" - checksum: 10/9de8597363a8e9b9952491ebe18167e3b36e7707569eed0ebf14f8bba773611376466ae34575bca8cfe3c767890c859c74056084738f09d4e4a6f902b2ad7d99 - languageName: node - linkType: hard - -"cpu-features@npm:~0.0.10": - version: 0.0.10 - resolution: "cpu-features@npm:0.0.10" - dependencies: - buildcheck: "npm:~0.0.6" - nan: "npm:^2.19.0" - node-gyp: "npm:latest" - checksum: 10/941b828ffe77582b2bdc03e894c913e2e2eeb5c6043ccb01338c34446d026f6888dc480ecb85e684809f9c3889d245f3648c7907eb61a92bdfc6aed039fcda8d - languageName: node - linkType: hard - -"crc-32@npm:^1.2.0": - version: 1.2.2 - resolution: "crc-32@npm:1.2.2" - bin: - crc32: bin/crc32.njs - checksum: 10/824f696a5baaf617809aa9cd033313c8f94f12d15ebffa69f10202480396be44aef9831d900ab291638a8022ed91c360696dd5b1ba691eb3f34e60be8835b7c3 - languageName: node - linkType: hard - -"crc32-stream@npm:^6.0.0": - version: 6.0.0 - resolution: "crc32-stream@npm:6.0.0" - dependencies: - crc-32: "npm:^1.2.0" - readable-stream: "npm:^4.0.0" - checksum: 10/e6edc2f81bc387daef6d18b2ac18c2ffcb01b554d3b5c7d8d29b177505aafffba574658fdd23922767e8dab1183d1962026c98c17e17fb272794c33293ef607c - languageName: node - linkType: hard - "create-jest@npm:^29.7.0": version: 29.7.0 resolution: "create-jest@npm:29.7.0" @@ -2491,15 +1640,6 @@ __metadata: languageName: node linkType: hard -"cross-fetch@npm:^4.0.0": - version: 4.1.0 - resolution: "cross-fetch@npm:4.1.0" - dependencies: - node-fetch: "npm:^2.7.0" - checksum: 10/07624940607b64777d27ec9c668ddb6649e8c59ee0a5a10e63a51ce857e2bbb1294a45854a31c10eccb91b65909a5b199fcb0217339b44156f85900a7384f489 - languageName: node - linkType: hard - "cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" @@ -2511,54 +1651,7 @@ __metadata: languageName: node linkType: hard -"data-uri-to-buffer@npm:^4.0.0": - version: 4.0.1 - resolution: "data-uri-to-buffer@npm:4.0.1" - checksum: 10/0d0790b67ffec5302f204c2ccca4494f70b4e2d940fea3d36b09f0bb2b8539c2e86690429eb1f1dc4bcc9e4df0644193073e63d9ee48ac9fce79ec1506e4aa4c - languageName: node - linkType: hard - -"data-view-buffer@npm:^1.0.2": - version: 1.0.2 - resolution: "data-view-buffer@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-data-view: "npm:^1.0.2" - checksum: 10/c10b155a4e93999d3a215d08c23eea95f865e1f510b2e7748fcae1882b776df1afe8c99f483ace7fc0e5a3193ab08da138abebc9829d12003746c5a338c4d644 - languageName: node - linkType: hard - -"data-view-byte-length@npm:^1.0.2": - version: 1.0.2 - resolution: "data-view-byte-length@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-data-view: "npm:^1.0.2" - checksum: 10/2a47055fcf1ab3ec41b00b6f738c6461a841391a643c9ed9befec1117c1765b4d492661d97fb7cc899200c328949dca6ff189d2c6537d96d60e8a02dfe3c95f7 - languageName: node - linkType: hard - -"data-view-byte-offset@npm:^1.0.1": - version: 1.0.1 - resolution: "data-view-byte-offset@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - is-data-view: "npm:^1.0.1" - checksum: 10/fa3bdfa0968bea6711ee50375094b39f561bce3f15f9e558df59de9c25f0bdd4cddc002d9c1d70ac7772ebd36854a7e22d1761e7302a934e6f1c2263bcf44aa2 - languageName: node - linkType: hard - -"dateformat@npm:^4.6.3": - version: 4.6.3 - resolution: "dateformat@npm:4.6.3" - checksum: 10/5c149c91bf9ce2142c89f84eee4c585f0cb1f6faf2536b1af89873f862666a28529d1ccafc44750aa01384da2197c4f76f4e149a3cc0c1cb2c46f5cc45f2bcb5 - languageName: node - linkType: hard - -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4": version: 4.4.0 resolution: "debug@npm:4.4.0" dependencies: @@ -2570,15 +1663,6 @@ __metadata: languageName: node linkType: hard -"debug@npm:^3.2.7": - version: 3.2.7 - resolution: "debug@npm:3.2.7" - dependencies: - ms: "npm:^2.1.1" - checksum: 10/d86fd7be2b85462297ea16f1934dc219335e802f629ca9a69b63ed8ed041dda492389bb2ee039217c02e5b54792b1c51aa96ae954cf28634d363a2360c7a1639 - languageName: node - linkType: hard - "dedent@npm:^1.0.0": version: 1.5.3 resolution: "dedent@npm:1.5.3" @@ -2605,35 +1689,6 @@ __metadata: languageName: node linkType: hard -"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": - version: 1.1.4 - resolution: "define-data-property@npm:1.1.4" - dependencies: - es-define-property: "npm:^1.0.0" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.0.1" - checksum: 10/abdcb2505d80a53524ba871273e5da75e77e52af9e15b3aa65d8aad82b8a3a424dad7aee2cc0b71470ac7acf501e08defac362e8b6a73cdb4309f028061df4ae - languageName: node - linkType: hard - -"define-lazy-prop@npm:^2.0.0": - version: 2.0.0 - resolution: "define-lazy-prop@npm:2.0.0" - checksum: 10/0115fdb065e0490918ba271d7339c42453d209d4cb619dfe635870d906731eff3e1ade8028bb461ea27ce8264ec5e22c6980612d332895977e89c1bbc80fcee2 - languageName: node - linkType: hard - -"define-properties@npm:^1.2.1": - version: 1.2.1 - resolution: "define-properties@npm:1.2.1" - dependencies: - define-data-property: "npm:^1.0.1" - has-property-descriptors: "npm:^1.0.0" - object-keys: "npm:^1.1.1" - checksum: 10/b4ccd00597dd46cb2d4a379398f5b19fca84a16f3374e2249201992f36b30f6835949a9429669ee6b41b6e837205a163eadd745e472069e70dfc10f03e5fcc12 - languageName: node - linkType: hard - "detect-newline@npm:^3.0.0": version: 3.1.0 resolution: "detect-newline@npm:3.1.0" @@ -2655,56 +1710,6 @@ __metadata: languageName: node linkType: hard -"dir-glob@npm:^3.0.1": - version: 3.0.1 - resolution: "dir-glob@npm:3.0.1" - dependencies: - path-type: "npm:^4.0.0" - checksum: 10/fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615 - languageName: node - linkType: hard - -"docker-compose@npm:^0.24.8": - version: 0.24.8 - resolution: "docker-compose@npm:0.24.8" - dependencies: - yaml: "npm:^2.2.2" - checksum: 10/2b8526f9797a55c819ff2d7dcea57085b012b3a3d77bc2e1a6b45c3fc9e82196312f5298cbe8299966462454a5ac8f68814bb407736b4385e0d226a2a39e877a - languageName: node - linkType: hard - -"docker-modem@npm:^3.0.0": - version: 3.0.8 - resolution: "docker-modem@npm:3.0.8" - dependencies: - debug: "npm:^4.1.1" - readable-stream: "npm:^3.5.0" - split-ca: "npm:^1.0.1" - ssh2: "npm:^1.11.0" - checksum: 10/a731d057b3da5a9da3dd9aff7e25bc33f2d29f3e0af947bd823d1361350071afb5b7cb0582af5bf012b08fca356520685bcff87bfcba08e85725576b32f264a2 - languageName: node - linkType: hard - -"dockerode@npm:^3.3.5": - version: 3.3.5 - resolution: "dockerode@npm:3.3.5" - dependencies: - "@balena/dockerignore": "npm:^1.0.2" - docker-modem: "npm:^3.0.0" - tar-fs: "npm:~2.0.1" - checksum: 10/1748e8d96f88fe71bb165a4c05726904937f5863b69eaeb4a3c1bb3bbf66940c7bef13b349ff757dc43664b4367611aab76f35c1ba468f07dcbaba567e6acd88 - languageName: node - linkType: hard - -"doctrine@npm:^2.1.0": - version: 2.1.0 - resolution: "doctrine@npm:2.1.0" - dependencies: - esutils: "npm:^2.0.2" - checksum: 10/555684f77e791b17173ea86e2eea45ef26c22219cb64670669c4f4bebd26dbc95cd90ec1f4159e9349a6bb9eb892ce4dde8cd0139e77bedd8bf4518238618474 - languageName: node - linkType: hard - "doctrine@npm:^3.0.0": version: 3.0.0 resolution: "doctrine@npm:3.0.0" @@ -2714,17 +1719,6 @@ __metadata: languageName: node linkType: hard -"dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "dunder-proto@npm:1.0.1" - dependencies: - call-bind-apply-helpers: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.2.0" - checksum: 10/5add88a3d68d42d6e6130a0cac450b7c2edbe73364bbd2fc334564418569bea97c6943a8fcd70e27130bf32afc236f30982fc4905039b703f23e9e0433c29934 - languageName: node - linkType: hard - "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -2732,7 +1726,7 @@ __metadata: languageName: node linkType: hard -"ejs@npm:^3.1.10, ejs@npm:^3.1.7": +"ejs@npm:^3.1.10": version: 3.1.10 resolution: "ejs@npm:3.1.10" dependencies: @@ -2780,15 +1774,6 @@ __metadata: languageName: node linkType: hard -"end-of-stream@npm:^1.1.0, end-of-stream@npm:^1.4.1": - version: 1.4.4 - resolution: "end-of-stream@npm:1.4.4" - dependencies: - once: "npm:^1.4.0" - checksum: 10/530a5a5a1e517e962854a31693dbb5c0b2fc40b46dad2a56a2deec656ca040631124f4795823acc68238147805f8b021abbe221f4afed5ef3c8e8efc2024908b - languageName: node - linkType: hard - "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -2797,290 +1782,39 @@ __metadata: linkType: hard "err-code@npm:^2.0.2": - version: 2.0.3 - resolution: "err-code@npm:2.0.3" - checksum: 10/1d20d825cdcce8d811bfbe86340f4755c02655a7feb2f13f8c880566d9d72a3f6c92c192a6867632e490d6da67b678271f46e01044996a6443e870331100dfdd - languageName: node - linkType: hard - -"error-ex@npm:^1.3.1": - version: 1.3.2 - resolution: "error-ex@npm:1.3.2" - dependencies: - is-arrayish: "npm:^0.2.1" - checksum: 10/d547740aa29c34e753fb6fed2c5de81802438529c12b3673bd37b6bb1fe49b9b7abdc3c11e6062fe625d8a296b3cf769a80f878865e25e685f787763eede3ffb - languageName: node - linkType: hard - -"es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.9": - version: 1.23.9 - resolution: "es-abstract@npm:1.23.9" - dependencies: - array-buffer-byte-length: "npm:^1.0.2" - arraybuffer.prototype.slice: "npm:^1.0.4" - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - data-view-buffer: "npm:^1.0.2" - data-view-byte-length: "npm:^1.0.2" - data-view-byte-offset: "npm:^1.0.1" - es-define-property: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - es-set-tostringtag: "npm:^2.1.0" - es-to-primitive: "npm:^1.3.0" - function.prototype.name: "npm:^1.1.8" - get-intrinsic: "npm:^1.2.7" - get-proto: "npm:^1.0.0" - get-symbol-description: "npm:^1.1.0" - globalthis: "npm:^1.0.4" - gopd: "npm:^1.2.0" - has-property-descriptors: "npm:^1.0.2" - has-proto: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - hasown: "npm:^2.0.2" - internal-slot: "npm:^1.1.0" - is-array-buffer: "npm:^3.0.5" - is-callable: "npm:^1.2.7" - is-data-view: "npm:^1.0.2" - is-regex: "npm:^1.2.1" - is-shared-array-buffer: "npm:^1.0.4" - is-string: "npm:^1.1.1" - is-typed-array: "npm:^1.1.15" - is-weakref: "npm:^1.1.0" - math-intrinsics: "npm:^1.1.0" - object-inspect: "npm:^1.13.3" - object-keys: "npm:^1.1.1" - object.assign: "npm:^4.1.7" - own-keys: "npm:^1.0.1" - regexp.prototype.flags: "npm:^1.5.3" - safe-array-concat: "npm:^1.1.3" - safe-push-apply: "npm:^1.0.0" - safe-regex-test: "npm:^1.1.0" - set-proto: "npm:^1.0.0" - string.prototype.trim: "npm:^1.2.10" - string.prototype.trimend: "npm:^1.0.9" - string.prototype.trimstart: "npm:^1.0.8" - typed-array-buffer: "npm:^1.0.3" - typed-array-byte-length: "npm:^1.0.3" - typed-array-byte-offset: "npm:^1.0.4" - typed-array-length: "npm:^1.0.7" - unbox-primitive: "npm:^1.1.0" - which-typed-array: "npm:^1.1.18" - checksum: 10/31a321966d760d88fc2ed984104841b42f4f24fc322b246002b9be0af162e03803ee41fcc3cf8be89e07a27ba3033168f877dd983703cb81422ffe5322a27582 - languageName: node - linkType: hard - -"es-define-property@npm:^1.0.0, es-define-property@npm:^1.0.1": - version: 1.0.1 - resolution: "es-define-property@npm:1.0.1" - checksum: 10/f8dc9e660d90919f11084db0a893128f3592b781ce967e4fccfb8f3106cb83e400a4032c559184ec52ee1dbd4b01e7776c7cd0b3327b1961b1a4a7008920fe78 - languageName: node - linkType: hard - -"es-errors@npm:^1.3.0": - version: 1.3.0 - resolution: "es-errors@npm:1.3.0" - checksum: 10/96e65d640156f91b707517e8cdc454dd7d47c32833aa3e85d79f24f9eb7ea85f39b63e36216ef0114996581969b59fe609a94e30316b08f5f4df1d44134cf8d5 - languageName: node - linkType: hard - -"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": - version: 1.1.1 - resolution: "es-object-atoms@npm:1.1.1" - dependencies: - es-errors: "npm:^1.3.0" - checksum: 10/54fe77de288451dae51c37bfbfe3ec86732dc3778f98f3eb3bdb4bf48063b2c0b8f9c93542656986149d08aa5be3204286e2276053d19582b76753f1a2728867 - languageName: node - linkType: hard - -"es-set-tostringtag@npm:^2.1.0": - version: 2.1.0 - resolution: "es-set-tostringtag@npm:2.1.0" - dependencies: - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - has-tostringtag: "npm:^1.0.2" - hasown: "npm:^2.0.2" - checksum: 10/86814bf8afbcd8966653f731415888019d4bc4aca6b6c354132a7a75bb87566751e320369654a101d23a91c87a85c79b178bcf40332839bd347aff437c4fb65f - languageName: node - linkType: hard - -"es-shim-unscopables@npm:^1.0.2": - version: 1.1.0 - resolution: "es-shim-unscopables@npm:1.1.0" - dependencies: - hasown: "npm:^2.0.2" - checksum: 10/c351f586c30bbabc62355be49564b2435468b52c3532b8a1663672e3d10dc300197e69c247869dd173e56d86423ab95fc0c10b0939cdae597094e0fdca078cba - languageName: node - linkType: hard - -"es-to-primitive@npm:^1.3.0": - version: 1.3.0 - resolution: "es-to-primitive@npm:1.3.0" - dependencies: - is-callable: "npm:^1.2.7" - is-date-object: "npm:^1.0.5" - is-symbol: "npm:^1.0.4" - checksum: 10/17faf35c221aad59a16286cbf58ef6f080bf3c485dff202c490d074d8e74da07884e29b852c245d894eac84f73c58330ec956dfd6d02c0b449d75eb1012a3f9b - languageName: node - linkType: hard - -"escalade@npm:^3.1.1, escalade@npm:^3.2.0": - version: 3.2.0 - resolution: "escalade@npm:3.2.0" - checksum: 10/9d7169e3965b2f9ae46971afa392f6e5a25545ea30f2e2dd99c9b0a95a3f52b5653681a84f5b2911a413ddad2d7a93d3514165072f349b5ffc59c75a899970d6 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^2.0.0": - version: 2.0.0 - resolution: "escape-string-regexp@npm:2.0.0" - checksum: 10/9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^4.0.0": - version: 4.0.0 - resolution: "escape-string-regexp@npm:4.0.0" - checksum: 10/98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5 - languageName: node - linkType: hard - -"eslint-compat-utils@npm:^0.5.1": - version: 0.5.1 - resolution: "eslint-compat-utils@npm:0.5.1" - dependencies: - semver: "npm:^7.5.4" - peerDependencies: - eslint: ">=6.0.0" - checksum: 10/ac65ac1c6107cf19f63f5fc17cea361c9cb1336be7356f23dbb0fac10979974b4622e13e950be43cbf431801f2c07f7dab448573181ccf6edc0b86d5b5304511 - languageName: node - linkType: hard - -"eslint-config-prettier@npm:^9.0.0": - version: 9.1.0 - resolution: "eslint-config-prettier@npm:9.1.0" - peerDependencies: - eslint: ">=7.0.0" - bin: - eslint-config-prettier: bin/cli.js - checksum: 10/411e3b3b1c7aa04e3e0f20d561271b3b909014956c4dba51c878bf1a23dbb8c800a3be235c46c4732c70827276e540b6eed4636d9b09b444fd0a8e07f0fcd830 - languageName: node - linkType: hard - -"eslint-import-resolver-node@npm:^0.3.9": - version: 0.3.9 - resolution: "eslint-import-resolver-node@npm:0.3.9" - dependencies: - debug: "npm:^3.2.7" - is-core-module: "npm:^2.13.0" - resolve: "npm:^1.22.4" - checksum: 10/d52e08e1d96cf630957272e4f2644dcfb531e49dcfd1edd2e07e43369eb2ec7a7d4423d417beee613201206ff2efa4eb9a582b5825ee28802fc7c71fcd53ca83 - languageName: node - linkType: hard - -"eslint-module-utils@npm:^2.12.0": - version: 2.12.0 - resolution: "eslint-module-utils@npm:2.12.0" - dependencies: - debug: "npm:^3.2.7" - peerDependenciesMeta: - eslint: - optional: true - checksum: 10/dd27791147eca17366afcb83f47d6825b6ce164abb256681e5de4ec1d7e87d8605641eb869298a0dbc70665e2446dbcc2f40d3e1631a9475dd64dd23d4ca5dee - languageName: node - linkType: hard - -"eslint-plugin-es-x@npm:^7.5.0": - version: 7.8.0 - resolution: "eslint-plugin-es-x@npm:7.8.0" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.1.2" - "@eslint-community/regexpp": "npm:^4.11.0" - eslint-compat-utils: "npm:^0.5.1" - peerDependencies: - eslint: ">=8" - checksum: 10/1df8d52c4fadc06854ce801af05b05f2642aa2deb918fb7d37738596eabd70b7f21a22b150b78ec9104bac6a1b6b4fb796adea2364ede91b01d20964849ce5f7 + version: 2.0.3 + resolution: "err-code@npm:2.0.3" + checksum: 10/1d20d825cdcce8d811bfbe86340f4755c02655a7feb2f13f8c880566d9d72a3f6c92c192a6867632e490d6da67b678271f46e01044996a6443e870331100dfdd languageName: node linkType: hard -"eslint-plugin-import@npm:^2.28.1": - version: 2.31.0 - resolution: "eslint-plugin-import@npm:2.31.0" +"error-ex@npm:^1.3.1": + version: 1.3.2 + resolution: "error-ex@npm:1.3.2" dependencies: - "@rtsao/scc": "npm:^1.1.0" - array-includes: "npm:^3.1.8" - array.prototype.findlastindex: "npm:^1.2.5" - array.prototype.flat: "npm:^1.3.2" - array.prototype.flatmap: "npm:^1.3.2" - debug: "npm:^3.2.7" - doctrine: "npm:^2.1.0" - eslint-import-resolver-node: "npm:^0.3.9" - eslint-module-utils: "npm:^2.12.0" - hasown: "npm:^2.0.2" - is-core-module: "npm:^2.15.1" - is-glob: "npm:^4.0.3" - minimatch: "npm:^3.1.2" - object.fromentries: "npm:^2.0.8" - object.groupby: "npm:^1.0.3" - object.values: "npm:^1.2.0" - semver: "npm:^6.3.1" - string.prototype.trimend: "npm:^1.0.8" - tsconfig-paths: "npm:^3.15.0" - peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - checksum: 10/6b76bd009ac2db0615d9019699d18e2a51a86cb8c1d0855a35fb1b418be23b40239e6debdc6e8c92c59f1468ed0ea8d7b85c817117a113d5cc225be8a02ad31c + is-arrayish: "npm:^0.2.1" + checksum: 10/d547740aa29c34e753fb6fed2c5de81802438529c12b3673bd37b6bb1fe49b9b7abdc3c11e6062fe625d8a296b3cf769a80f878865e25e685f787763eede3ffb languageName: node linkType: hard -"eslint-plugin-n@npm:^16.2.0": - version: 16.6.2 - resolution: "eslint-plugin-n@npm:16.6.2" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.4.0" - builtins: "npm:^5.0.1" - eslint-plugin-es-x: "npm:^7.5.0" - get-tsconfig: "npm:^4.7.0" - globals: "npm:^13.24.0" - ignore: "npm:^5.2.4" - is-builtin-module: "npm:^3.2.1" - is-core-module: "npm:^2.12.1" - minimatch: "npm:^3.1.2" - resolve: "npm:^1.22.2" - semver: "npm:^7.5.3" - peerDependencies: - eslint: ">=7.0.0" - checksum: 10/e0f600d03d3a3df57e9a811648b1b534a6d67c90ea9406340ddf3763c2b87cf5ef910b390f787ca5cb27c8d8ff36aad42d70209b54e2a1cb4cc2507ca417229a +"escalade@npm:^3.1.1, escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10/9d7169e3965b2f9ae46971afa392f6e5a25545ea30f2e2dd99c9b0a95a3f52b5653681a84f5b2911a413ddad2d7a93d3514165072f349b5ffc59c75a899970d6 languageName: node linkType: hard -"eslint-plugin-prettier@npm:^5.0.1": - version: 5.2.3 - resolution: "eslint-plugin-prettier@npm:5.2.3" - dependencies: - prettier-linter-helpers: "npm:^1.0.0" - synckit: "npm:^0.9.1" - peerDependencies: - "@types/eslint": ">=8.0.0" - eslint: ">=8.0.0" - eslint-config-prettier: "*" - prettier: ">=3.0.0" - peerDependenciesMeta: - "@types/eslint": - optional: true - eslint-config-prettier: - optional: true - checksum: 10/6444a0b89f3e2a6b38adce69761133f8539487d797f1655b3fa24f93a398be132c4f68f87041a14740b79202368d5782aa1dffd2bd7a3ea659f263d6796acf15 +"escape-string-regexp@npm:^2.0.0": + version: 2.0.0 + resolution: "escape-string-regexp@npm:2.0.0" + checksum: 10/9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 languageName: node linkType: hard -"eslint-plugin-promise@npm:^6.1.1": - version: 6.6.0 - resolution: "eslint-plugin-promise@npm:6.6.0" - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - checksum: 10/c2b5604efd7e1390c132fcbf06cb2f072c956ffa65c14a991cb74ba1e2327357797239cb5b9b292d5e4010301bb897bd85a6273d7873fb157edc46aa2d95cbd9 +"escape-string-regexp@npm:^4.0.0": + version: 4.0.0 + resolution: "escape-string-regexp@npm:4.0.0" + checksum: 10/98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5 languageName: node linkType: hard @@ -3202,20 +1936,6 @@ __metadata: languageName: node linkType: hard -"event-target-shim@npm:^5.0.0": - version: 5.0.1 - resolution: "event-target-shim@npm:5.0.1" - checksum: 10/49ff46c3a7facbad3decb31f597063e761785d7fdb3920d4989d7b08c97a61c2f51183e2f3a03130c9088df88d4b489b1b79ab632219901f184f85158508f4c8 - languageName: node - linkType: hard - -"events@npm:^3.3.0": - version: 3.3.0 - resolution: "events@npm:3.3.0" - checksum: 10/a3d47e285e28d324d7180f1e493961a2bbb4cad6412090e4dec114f4db1f5b560c7696ee8e758f55e23913ede856e3689cd3aa9ae13c56b5d8314cd3b3ddd1be - languageName: node - linkType: hard - "execa@npm:^5.0.0": version: 5.1.1 resolution: "execa@npm:5.1.1" @@ -3269,13 +1989,6 @@ __metadata: languageName: node linkType: hard -"fast-copy@npm:^3.0.0": - version: 3.0.2 - resolution: "fast-copy@npm:3.0.2" - checksum: 10/97e1022e2aaa27acf4a986d679310bfd66bfb87fe8da9dd33b698e3e50189484001cf1eeb9670e19b59d9d299828ed86c8da354c954f125995ab2a6331c5f290 - languageName: node - linkType: hard - "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -3283,33 +1996,6 @@ __metadata: languageName: node linkType: hard -"fast-diff@npm:^1.1.2": - version: 1.3.0 - resolution: "fast-diff@npm:1.3.0" - checksum: 10/9e57415bc69cd6efcc720b3b8fe9fdaf42dcfc06f86f0f45378b1fa512598a8aac48aa3928c8751d58e2f01bb4ba4f07e4f3d9bc0d57586d45f1bd1e872c6cde - languageName: node - linkType: hard - -"fast-fifo@npm:^1.2.0, fast-fifo@npm:^1.3.2": - version: 1.3.2 - resolution: "fast-fifo@npm:1.3.2" - checksum: 10/6bfcba3e4df5af7be3332703b69a7898a8ed7020837ec4395bb341bd96cc3a6d86c3f6071dd98da289618cf2234c70d84b2a6f09a33dd6f988b1ff60d8e54275 - languageName: node - linkType: hard - -"fast-glob@npm:^3.2.9": - version: 3.3.3 - resolution: "fast-glob@npm:3.3.3" - dependencies: - "@nodelib/fs.stat": "npm:^2.0.2" - "@nodelib/fs.walk": "npm:^1.2.3" - glob-parent: "npm:^5.1.2" - merge2: "npm:^1.3.0" - micromatch: "npm:^4.0.8" - checksum: 10/dcc6432b269762dd47381d8b8358bf964d8f4f60286ac6aa41c01ade70bda459ff2001b516690b96d5365f68a49242966112b5d5cc9cd82395fa8f9d017c90ad - languageName: node - linkType: hard - "fast-json-stable-stringify@npm:2.x, fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" @@ -3324,20 +2010,6 @@ __metadata: languageName: node linkType: hard -"fast-redact@npm:^3.1.1": - version: 3.5.0 - resolution: "fast-redact@npm:3.5.0" - checksum: 10/24b27e2023bd5a62f908d97a753b1adb8d89206b260f97727728e00b693197dea2fc2aa3711147a385d0ec6e713569fd533df37a4ef947e08cb65af3019c7ad5 - languageName: node - linkType: hard - -"fast-safe-stringify@npm:^2.1.1": - version: 2.1.1 - resolution: "fast-safe-stringify@npm:2.1.1" - checksum: 10/dc1f063c2c6ac9533aee14d406441f86783a8984b2ca09b19c2fe281f9ff59d315298bc7bc22fd1f83d26fe19ef2f20e2ddb68e96b15040292e555c5ced0c1e4 - languageName: node - linkType: hard - "fastq@npm:^1.6.0": version: 1.19.1 resolution: "fastq@npm:1.19.1" @@ -3356,16 +2028,6 @@ __metadata: languageName: node linkType: hard -"fetch-blob@npm:^3.1.2, fetch-blob@npm:^3.1.4": - version: 3.2.0 - resolution: "fetch-blob@npm:3.2.0" - dependencies: - node-domexception: "npm:^1.0.0" - web-streams-polyfill: "npm:^3.0.3" - checksum: 10/5264ecceb5fdc19eb51d1d0359921f12730941e333019e673e71eb73921146dceabcb0b8f534582be4497312d656508a439ad0f5edeec2b29ab2e10c72a1f86b - languageName: node - linkType: hard - "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -3431,15 +2093,6 @@ __metadata: languageName: node linkType: hard -"for-each@npm:^0.3.3": - version: 0.3.5 - resolution: "for-each@npm:0.3.5" - dependencies: - is-callable: "npm:^1.2.7" - checksum: 10/330cc2439f85c94f4609de3ee1d32c5693ae15cdd7fe3d112c4fd9efd4ce7143f2c64ef6c2c9e0cfdb0058437f33ef05b5bdae5b98fcc903fb2143fbaf0fea0f - languageName: node - linkType: hard - "foreground-child@npm:^3.1.0": version: 3.3.1 resolution: "foreground-child@npm:3.3.1" @@ -3450,40 +2103,6 @@ __metadata: languageName: node linkType: hard -"formdata-polyfill@npm:^4.0.10": - version: 4.0.10 - resolution: "formdata-polyfill@npm:4.0.10" - dependencies: - fetch-blob: "npm:^3.1.2" - checksum: 10/9b5001d2edef3c9449ac3f48bd4f8cc92e7d0f2e7c1a5c8ba555ad4e77535cc5cf621fabe49e97f304067037282dd9093b9160a3cb533e46420b446c4e6bc06f - languageName: node - linkType: hard - -"fp-ts@npm:^2.16.1": - version: 2.16.9 - resolution: "fp-ts@npm:2.16.9" - checksum: 10/af5c3fa829456da60ed63b5288907868f0df01a7215acfc5697f621a21f76b0a0f7b7c08ac81f2bcf7ecae13a6c6d41047e739a79cf239db19cd49afd7e8e015 - languageName: node - linkType: hard - -"fs-constants@npm:^1.0.0": - version: 1.0.0 - resolution: "fs-constants@npm:1.0.0" - checksum: 10/18f5b718371816155849475ac36c7d0b24d39a11d91348cfcb308b4494824413e03572c403c86d3a260e049465518c4f0d5bd00f0371cdfcad6d4f30a85b350d - languageName: node - linkType: hard - -"fs-extra@npm:^10.0.0": - version: 10.1.0 - resolution: "fs-extra@npm:10.1.0" - dependencies: - graceful-fs: "npm:^4.2.0" - jsonfile: "npm:^6.0.1" - universalify: "npm:^2.0.0" - checksum: 10/05ce2c3b59049bcb7b52001acd000e44b3c4af4ec1f8839f383ef41ec0048e3cfa7fd8a637b1bddfefad319145db89be91f4b7c1db2908205d38bf91e7d1d3b7 - languageName: node - linkType: hard - "fs-minipass@npm:^3.0.0": version: 3.0.3 resolution: "fs-minipass@npm:3.0.3" @@ -3526,27 +2145,6 @@ __metadata: languageName: node linkType: hard -"function.prototype.name@npm:^1.1.6, function.prototype.name@npm:^1.1.8": - version: 1.1.8 - resolution: "function.prototype.name@npm:1.1.8" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - functions-have-names: "npm:^1.2.3" - hasown: "npm:^2.0.2" - is-callable: "npm:^1.2.7" - checksum: 10/25b9e5bea936732a6f0c0c08db58cc0d609ac1ed458c6a07ead46b32e7b9bf3fe5887796c3f83d35994efbc4fdde81c08ac64135b2c399b8f2113968d44082bc - languageName: node - linkType: hard - -"functions-have-names@npm:^1.2.3": - version: 1.2.3 - resolution: "functions-have-names@npm:1.2.3" - checksum: 10/0ddfd3ed1066a55984aaecebf5419fbd9344a5c38dd120ffb0739fac4496758dcf371297440528b115e4367fc46e3abc86a2cc0ff44612181b175ae967a11a05 - languageName: node - linkType: hard - "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" @@ -3561,24 +2159,6 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7": - version: 1.3.0 - resolution: "get-intrinsic@npm:1.3.0" - dependencies: - call-bind-apply-helpers: "npm:^1.0.2" - es-define-property: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - function-bind: "npm:^1.1.2" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - hasown: "npm:^2.0.2" - math-intrinsics: "npm:^1.1.0" - checksum: 10/6e9dd920ff054147b6f44cb98104330e87caafae051b6d37b13384a45ba15e71af33c3baeac7cb630a0aaa23142718dcf25b45cfdd86c184c5dcb4e56d953a10 - languageName: node - linkType: hard - "get-package-type@npm:^0.1.0": version: 0.1.0 resolution: "get-package-type@npm:0.1.0" @@ -3586,23 +2166,6 @@ __metadata: languageName: node linkType: hard -"get-port@npm:^5.1.1": - version: 5.1.1 - resolution: "get-port@npm:5.1.1" - checksum: 10/0162663ffe5c09e748cd79d97b74cd70e5a5c84b760a475ce5767b357fb2a57cb821cee412d646aa8a156ed39b78aab88974eddaa9e5ee926173c036c0713787 - languageName: node - linkType: hard - -"get-proto@npm:^1.0.0, get-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "get-proto@npm:1.0.1" - dependencies: - dunder-proto: "npm:^1.0.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10/4fc96afdb58ced9a67558698b91433e6b037aaa6f1493af77498d7c85b141382cf223c0e5946f334fb328ee85dfe6edd06d218eaf09556f4bc4ec6005d7f5f7b - languageName: node - linkType: hard - "get-stream@npm:^6.0.0": version: 6.0.1 resolution: "get-stream@npm:6.0.1" @@ -3610,35 +2173,6 @@ __metadata: languageName: node linkType: hard -"get-symbol-description@npm:^1.1.0": - version: 1.1.0 - resolution: "get-symbol-description@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - checksum: 10/a353e3a9595a74720b40fb5bae3ba4a4f826e186e83814d93375182384265676f59e49998b9cdfac4a2225ce95a3d32a68f502a2c5619303987f1c183ab80494 - languageName: node - linkType: hard - -"get-tsconfig@npm:^4.7.0": - version: 4.10.0 - resolution: "get-tsconfig@npm:4.10.0" - dependencies: - resolve-pkg-maps: "npm:^1.0.0" - checksum: 10/5259b5c99a1957114337d9d0603b4a305ec9e29fa6cac7d2fbf634ba6754a0cc88bfd281a02416ce64e604b637d3cb239185381a79a5842b17fb55c097b38c4b - languageName: node - linkType: hard - -"glob-parent@npm:^5.1.2": - version: 5.1.2 - resolution: "glob-parent@npm:5.1.2" - dependencies: - is-glob: "npm:^4.0.1" - checksum: 10/32cd106ce8c0d83731966d31517adb766d02c3812de49c30cfe0675c7c0ae6630c11214c54a5ae67aca882cf738d27fd7768f21aa19118b9245950554be07247 - languageName: node - linkType: hard - "glob-parent@npm:^6.0.2": version: 6.0.2 resolution: "glob-parent@npm:6.0.2" @@ -3648,7 +2182,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.0.0, glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7": +"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7": version: 10.4.5 resolution: "glob@npm:10.4.5" dependencies: @@ -3685,7 +2219,7 @@ __metadata: languageName: node linkType: hard -"globals@npm:^13.19.0, globals@npm:^13.24.0": +"globals@npm:^13.19.0": version: 13.24.0 resolution: "globals@npm:13.24.0" dependencies: @@ -3694,38 +2228,7 @@ __metadata: languageName: node linkType: hard -"globalthis@npm:^1.0.4": - version: 1.0.4 - resolution: "globalthis@npm:1.0.4" - dependencies: - define-properties: "npm:^1.2.1" - gopd: "npm:^1.0.1" - checksum: 10/1f1fd078fb2f7296306ef9dd51019491044ccf17a59ed49d375b576ca108ff37e47f3d29aead7add40763574a992f16a5367dd1e2173b8634ef18556ab719ac4 - languageName: node - linkType: hard - -"globby@npm:^11.1.0": - version: 11.1.0 - resolution: "globby@npm:11.1.0" - dependencies: - array-union: "npm:^2.1.0" - dir-glob: "npm:^3.0.1" - fast-glob: "npm:^3.2.9" - ignore: "npm:^5.2.0" - merge2: "npm:^1.4.1" - slash: "npm:^3.0.0" - checksum: 10/288e95e310227bbe037076ea81b7c2598ccbc3122d87abc6dab39e1eec309aa14f0e366a98cdc45237ffcfcbad3db597778c0068217dcb1950fef6249104e1b1 - languageName: node - linkType: hard - -"gopd@npm:^1.0.1, gopd@npm:^1.2.0": - version: 1.2.0 - resolution: "gopd@npm:1.2.0" - checksum: 10/94e296d69f92dc1c0768fcfeecfb3855582ab59a7c75e969d5f96ce50c3d201fd86d5a2857c22565764d5bb8a816c7b1e58f133ec318cd56274da36c5e3fb1a1 - languageName: node - linkType: hard - -"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 @@ -3739,40 +2242,6 @@ __metadata: languageName: node linkType: hard -"graphql-tag@npm:^2.12.6": - version: 2.12.6 - resolution: "graphql-tag@npm:2.12.6" - dependencies: - tslib: "npm:^2.1.0" - peerDependencies: - graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 10/23a2bc1d3fbeae86444204e0ac08522e09dc369559ba75768e47421a7321b59f352fb5b2c9a5c37d3cf6de890dca4e5ac47e740c7cc622e728572ecaa649089e - languageName: node - linkType: hard - -"graphql-ws@npm:^5.14.0": - version: 5.16.2 - resolution: "graphql-ws@npm:5.16.2" - peerDependencies: - graphql: ">=0.11 <=16" - checksum: 10/6647bfe640b467f27aaf5ee044c1d114fe266e82cda4ebbb4368d5a4e98df5d2de9d6be70d28eb5e821d87fbf8964c3a8a18abf87c76d4f148800fd8e0488c3d - languageName: node - linkType: hard - -"graphql@npm:^16.8.0": - version: 16.10.0 - resolution: "graphql@npm:16.10.0" - checksum: 10/d42cf81ddcf3a61dfb213217576bf33c326f15b02c4cee369b373dc74100cbdcdc4479b3b797e79b654dabd8fddf50ef65ff75420e9ce5596c02e21f24c9126a - languageName: node - linkType: hard - -"has-bigints@npm:^1.0.2": - version: 1.1.0 - resolution: "has-bigints@npm:1.1.0" - checksum: 10/90fb1b24d40d2472bcd1c8bd9dd479037ec240215869bdbff97b2be83acef57d28f7e96bdd003a21bed218d058b49097f4acc8821c05b1629cc5d48dd7bfcccd - languageName: node - linkType: hard - "has-flag@npm:^4.0.0": version: 4.0.0 resolution: "has-flag@npm:4.0.0" @@ -3780,40 +2249,6 @@ __metadata: languageName: node linkType: hard -"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.2": - version: 1.0.2 - resolution: "has-property-descriptors@npm:1.0.2" - dependencies: - es-define-property: "npm:^1.0.0" - checksum: 10/2d8c9ab8cebb572e3362f7d06139a4592105983d4317e68f7adba320fe6ddfc8874581e0971e899e633fd5f72e262830edce36d5a0bc863dad17ad20572484b2 - languageName: node - linkType: hard - -"has-proto@npm:^1.2.0": - version: 1.2.0 - resolution: "has-proto@npm:1.2.0" - dependencies: - dunder-proto: "npm:^1.0.0" - checksum: 10/7eaed07728eaa28b77fadccabce53f30de467ff186a766872669a833ac2e87d8922b76a22cc58339d7e0277aefe98d6d00762113b27a97cdf65adcf958970935 - languageName: node - linkType: hard - -"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": - version: 1.1.0 - resolution: "has-symbols@npm:1.1.0" - checksum: 10/959385c98696ebbca51e7534e0dc723ada325efa3475350951363cce216d27373e0259b63edb599f72eb94d6cde8577b4b2375f080b303947e560f85692834fa - languageName: node - linkType: hard - -"has-tostringtag@npm:^1.0.2": - version: 1.0.2 - resolution: "has-tostringtag@npm:1.0.2" - dependencies: - has-symbols: "npm:^1.0.3" - checksum: 10/c74c5f5ceee3c8a5b8bc37719840dc3749f5b0306d818974141dda2471a1a2ca6c8e46b9d6ac222c5345df7a901c9b6f350b1e6d62763fec877e26609a401bfe - languageName: node - linkType: hard - "hasown@npm:^2.0.2": version: 2.0.2 resolution: "hasown@npm:2.0.2" @@ -3823,22 +2258,6 @@ __metadata: languageName: node linkType: hard -"help-me@npm:^5.0.0": - version: 5.0.0 - resolution: "help-me@npm:5.0.0" - checksum: 10/5f99bd91dae93d02867175c3856c561d7e3a24f16999b08f5fc79689044b938d7ed58457f4d8c8744c01403e6e0470b7896baa344d112b2355842fd935a75d69 - languageName: node - linkType: hard - -"hoist-non-react-statics@npm:^3.3.2": - version: 3.3.2 - resolution: "hoist-non-react-statics@npm:3.3.2" - dependencies: - react-is: "npm:^16.7.0" - checksum: 10/1acbe85f33e5a39f90c822ad4d28b24daeb60f71c545279431dc98c312cd28a54f8d64788e477fe21dc502b0e3cf58589ebe5c1ad22af27245370391c2d24ea6 - languageName: node - linkType: hard - "html-escaper@npm:^2.0.0": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" @@ -3889,14 +2308,7 @@ __metadata: languageName: node linkType: hard -"ieee754@npm:^1.1.13, ieee754@npm:^1.2.1": - version: 1.2.1 - resolution: "ieee754@npm:1.2.1" - checksum: 10/d9f2557a59036f16c282aaeb107832dc957a93d73397d89bbad4eb1130560560eb695060145e8e6b3b498b15ab95510226649a0b8f52ae06583575419fe10fc4 - languageName: node - linkType: hard - -"ignore@npm:^5.2.0, ignore@npm:^5.2.4": +"ignore@npm:^5.2.0": version: 5.3.2 resolution: "ignore@npm:5.3.2" checksum: 10/cceb6a457000f8f6a50e1196429750d782afce5680dd878aa4221bd79972d68b3a55b4b1458fc682be978f4d3c6a249046aa0880637367216444ab7b014cfc98 @@ -3917,142 +2329,56 @@ __metadata: version: 3.2.0 resolution: "import-local@npm:3.2.0" dependencies: - pkg-dir: "npm:^4.2.0" - resolve-cwd: "npm:^3.0.0" - bin: - import-local-fixture: fixtures/cli.js - checksum: 10/0b0b0b412b2521739fbb85eeed834a3c34de9bc67e670b3d0b86248fc460d990a7b116ad056c084b87a693ef73d1f17268d6a5be626bb43c998a8b1c8a230004 - languageName: node - linkType: hard - -"imurmurhash@npm:^0.1.4": - version: 0.1.4 - resolution: "imurmurhash@npm:0.1.4" - checksum: 10/2d30b157a91fe1c1d7c6f653cbf263f039be6c5bfa959245a16d4ee191fc0f2af86c08545b6e6beeb041c56b574d2d5b9f95343d378ab49c0f37394d541e7fc8 - languageName: node - linkType: hard - -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: "npm:^1.3.0" - wrappy: "npm:1" - checksum: 10/d2ebd65441a38c8336c223d1b80b921b9fa737e37ea466fd7e253cb000c64ae1f17fa59e68130ef5bda92cfd8d36b83d37dab0eb0a4558bcfec8e8cdfd2dcb67 - languageName: node - linkType: hard - -"inherits@npm:2, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 10/cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521 - languageName: node - linkType: hard - -"internal-slot@npm:^1.1.0": - version: 1.1.0 - resolution: "internal-slot@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - hasown: "npm:^2.0.2" - side-channel: "npm:^1.1.0" - checksum: 10/1d5219273a3dab61b165eddf358815eefc463207db33c20fcfca54717da02e3f492003757721f972fd0bf21e4b426cab389c5427b99ceea4b8b670dc88ee6d4a - languageName: node - linkType: hard - -"io-ts@npm:^2.2.20": - version: 2.2.22 - resolution: "io-ts@npm:2.2.22" - peerDependencies: - fp-ts: ^2.5.0 - checksum: 10/c5eb8ca848f6e9586b5430773c62c8577902a6ca621349339e4d238c9ac4aba8df8de3e4d4317ff6593dcf38eb804445e0a5ba87afd7a2b8d29344ea9b6dc151 - languageName: node - linkType: hard - -"ip-address@npm:^9.0.5": - version: 9.0.5 - resolution: "ip-address@npm:9.0.5" - dependencies: - jsbn: "npm:1.1.0" - sprintf-js: "npm:^1.1.3" - checksum: 10/1ed81e06721af012306329b31f532b5e24e00cb537be18ddc905a84f19fe8f83a09a1699862bf3a1ec4b9dea93c55a3fa5faf8b5ea380431469df540f38b092c - languageName: node - linkType: hard - -"is-array-buffer@npm:^3.0.4, is-array-buffer@npm:^3.0.5": - version: 3.0.5 - resolution: "is-array-buffer@npm:3.0.5" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - get-intrinsic: "npm:^1.2.6" - checksum: 10/ef1095c55b963cd0dcf6f88a113e44a0aeca91e30d767c475e7d746d28d1195b10c5076b94491a7a0cd85020ca6a4923070021d74651d093dc909e9932cf689b - languageName: node - linkType: hard - -"is-arrayish@npm:^0.2.1": - version: 0.2.1 - resolution: "is-arrayish@npm:0.2.1" - checksum: 10/73ced84fa35e59e2c57da2d01e12cd01479f381d7f122ce41dcbb713f09dbfc651315832cd2bf8accba7681a69e4d6f1e03941d94dd10040d415086360e7005e - languageName: node - linkType: hard - -"is-async-function@npm:^2.0.0": - version: 2.1.1 - resolution: "is-async-function@npm:2.1.1" - dependencies: - async-function: "npm:^1.0.0" - call-bound: "npm:^1.0.3" - get-proto: "npm:^1.0.1" - has-tostringtag: "npm:^1.0.2" - safe-regex-test: "npm:^1.1.0" - checksum: 10/7c2ac7efdf671e03265e74a043bcb1c0a32e226bc2a42dfc5ec8644667df668bbe14b91c08e6c1414f392f8cf86cd1d489b3af97756e2c7a49dd1ba63fd40ca6 + pkg-dir: "npm:^4.2.0" + resolve-cwd: "npm:^3.0.0" + bin: + import-local-fixture: fixtures/cli.js + checksum: 10/0b0b0b412b2521739fbb85eeed834a3c34de9bc67e670b3d0b86248fc460d990a7b116ad056c084b87a693ef73d1f17268d6a5be626bb43c998a8b1c8a230004 languageName: node linkType: hard -"is-bigint@npm:^1.1.0": - version: 1.1.0 - resolution: "is-bigint@npm:1.1.0" - dependencies: - has-bigints: "npm:^1.0.2" - checksum: 10/10cf327310d712fe227cfaa32d8b11814c214392b6ac18c827f157e1e85363cf9c8e2a22df526689bd5d25e53b58cc110894787afb54e138e7c504174dba15fd +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 10/2d30b157a91fe1c1d7c6f653cbf263f039be6c5bfa959245a16d4ee191fc0f2af86c08545b6e6beeb041c56b574d2d5b9f95343d378ab49c0f37394d541e7fc8 languageName: node linkType: hard -"is-boolean-object@npm:^1.2.1": - version: 1.2.2 - resolution: "is-boolean-object@npm:1.2.2" +"inflight@npm:^1.0.4": + version: 1.0.6 + resolution: "inflight@npm:1.0.6" dependencies: - call-bound: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.2" - checksum: 10/051fa95fdb99d7fbf653165a7e6b2cba5d2eb62f7ffa81e793a790f3fb5366c91c1b7b6af6820aa2937dd86c73aa3ca9d9ca98f500988457b1c59692c52ba911 + once: "npm:^1.3.0" + wrappy: "npm:1" + checksum: 10/d2ebd65441a38c8336c223d1b80b921b9fa737e37ea466fd7e253cb000c64ae1f17fa59e68130ef5bda92cfd8d36b83d37dab0eb0a4558bcfec8e8cdfd2dcb67 languageName: node linkType: hard -"is-buffer@npm:^2.0.5": - version: 2.0.5 - resolution: "is-buffer@npm:2.0.5" - checksum: 10/3261a8b858edcc6c9566ba1694bf829e126faa88911d1c0a747ea658c5d81b14b6955e3a702d59dabadd58fdd440c01f321aa71d6547105fd21d03f94d0597e7 +"inherits@npm:2": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 10/cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521 languageName: node linkType: hard -"is-builtin-module@npm:^3.2.1": - version: 3.2.1 - resolution: "is-builtin-module@npm:3.2.1" +"ip-address@npm:^9.0.5": + version: 9.0.5 + resolution: "ip-address@npm:9.0.5" dependencies: - builtin-modules: "npm:^3.3.0" - checksum: 10/e8f0ffc19a98240bda9c7ada84d846486365af88d14616e737d280d378695c8c448a621dcafc8332dbf0fcd0a17b0763b845400709963fa9151ddffece90ae88 + jsbn: "npm:1.1.0" + sprintf-js: "npm:^1.1.3" + checksum: 10/1ed81e06721af012306329b31f532b5e24e00cb537be18ddc905a84f19fe8f83a09a1699862bf3a1ec4b9dea93c55a3fa5faf8b5ea380431469df540f38b092c languageName: node linkType: hard -"is-callable@npm:^1.2.7": - version: 1.2.7 - resolution: "is-callable@npm:1.2.7" - checksum: 10/48a9297fb92c99e9df48706241a189da362bff3003354aea4048bd5f7b2eb0d823cd16d0a383cece3d76166ba16d85d9659165ac6fcce1ac12e6c649d66dbdb9 +"is-arrayish@npm:^0.2.1": + version: 0.2.1 + resolution: "is-arrayish@npm:0.2.1" + checksum: 10/73ced84fa35e59e2c57da2d01e12cd01479f381d7f122ce41dcbb713f09dbfc651315832cd2bf8accba7681a69e4d6f1e03941d94dd10040d415086360e7005e languageName: node linkType: hard -"is-core-module@npm:^2.12.1, is-core-module@npm:^2.13.0, is-core-module@npm:^2.15.1, is-core-module@npm:^2.16.0": +"is-core-module@npm:^2.16.0": version: 2.16.1 resolution: "is-core-module@npm:2.16.1" dependencies: @@ -4061,36 +2387,6 @@ __metadata: languageName: node linkType: hard -"is-data-view@npm:^1.0.1, is-data-view@npm:^1.0.2": - version: 1.0.2 - resolution: "is-data-view@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.2" - get-intrinsic: "npm:^1.2.6" - is-typed-array: "npm:^1.1.13" - checksum: 10/357e9a48fa38f369fd6c4c3b632a3ab2b8adca14997db2e4b3fe94c4cd0a709af48e0fb61b02c64a90c0dd542fd489d49c2d03157b05ae6c07f5e4dec9e730a8 - languageName: node - linkType: hard - -"is-date-object@npm:^1.0.5, is-date-object@npm:^1.1.0": - version: 1.1.0 - resolution: "is-date-object@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.2" - has-tostringtag: "npm:^1.0.2" - checksum: 10/3a811b2c3176fb31abee1d23d3dc78b6c65fd9c07d591fcb67553cab9e7f272728c3dd077d2d738b53f9a2103255b0a6e8dfc9568a7805c56a78b2563e8d1dec - languageName: node - linkType: hard - -"is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": - version: 2.2.1 - resolution: "is-docker@npm:2.2.1" - bin: - is-docker: cli.js - checksum: 10/3fef7ddbf0be25958e8991ad941901bf5922ab2753c46980b60b05c1bf9c9c2402d35e6dc32e4380b980ef5e1970a5d9d5e5aa2e02d77727c3b6b5e918474c56 - languageName: node - linkType: hard - "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" @@ -4098,15 +2394,6 @@ __metadata: languageName: node linkType: hard -"is-finalizationregistry@npm:^1.1.0": - version: 1.1.1 - resolution: "is-finalizationregistry@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - checksum: 10/0bfb145e9a1ba852ddde423b0926d2169ae5fe9e37882cde9e8f69031281a986308df4d982283e152396e88b86562ed2256cbaa5e6390fb840a4c25ab54b8a80 - languageName: node - linkType: hard - "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -4121,19 +2408,7 @@ __metadata: languageName: node linkType: hard -"is-generator-function@npm:^1.0.10": - version: 1.1.0 - resolution: "is-generator-function@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.3" - get-proto: "npm:^1.0.0" - has-tostringtag: "npm:^1.0.2" - safe-regex-test: "npm:^1.1.0" - checksum: 10/5906ff51a856a5fbc6b90a90fce32040b0a6870da905f98818f1350f9acadfc9884f7c3dec833fce04b83dd883937b86a190b6593ede82e8b1af8b6c4ecf7cbd - languageName: node - linkType: hard - -"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3": +"is-glob@npm:^4.0.0, is-glob@npm:^4.0.3": version: 4.0.3 resolution: "is-glob@npm:4.0.3" dependencies: @@ -4142,23 +2417,6 @@ __metadata: languageName: node linkType: hard -"is-map@npm:^2.0.3": - version: 2.0.3 - resolution: "is-map@npm:2.0.3" - checksum: 10/8de7b41715b08bcb0e5edb0fb9384b80d2d5bcd10e142188f33247d19ff078abaf8e9b6f858e2302d8d05376a26a55cd23a3c9f8ab93292b02fcd2cc9e4e92bb - languageName: node - linkType: hard - -"is-number-object@npm:^1.1.1": - version: 1.1.1 - resolution: "is-number-object@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.2" - checksum: 10/a5922fb8779ab1ea3b8a9c144522b3d0bea5d9f8f23f7a72470e61e1e4df47714e28e0154ac011998b709cce260c3c9447ad3cd24a96c2f2a0abfdb2cbdc76c8 - languageName: node - linkType: hard - "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" @@ -4173,127 +2431,13 @@ __metadata: languageName: node linkType: hard -"is-regex@npm:^1.2.1": - version: 1.2.1 - resolution: "is-regex@npm:1.2.1" - dependencies: - call-bound: "npm:^1.0.2" - gopd: "npm:^1.2.0" - has-tostringtag: "npm:^1.0.2" - hasown: "npm:^2.0.2" - checksum: 10/c42b7efc5868a5c9a4d8e6d3e9816e8815c611b09535c00fead18a1138455c5cb5e1887f0023a467ad3f9c419d62ba4dc3d9ba8bafe55053914d6d6454a945d2 - languageName: node - linkType: hard - -"is-set@npm:^2.0.3": - version: 2.0.3 - resolution: "is-set@npm:2.0.3" - checksum: 10/5685df33f0a4a6098a98c72d94d67cad81b2bc72f1fb2091f3d9283c4a1c582123cd709145b02a9745f0ce6b41e3e43f1c944496d1d74d4ea43358be61308669 - languageName: node - linkType: hard - -"is-shared-array-buffer@npm:^1.0.4": - version: 1.0.4 - resolution: "is-shared-array-buffer@npm:1.0.4" - dependencies: - call-bound: "npm:^1.0.3" - checksum: 10/0380d7c60cc692856871526ffcd38a8133818a2ee42d47bb8008248a0cd2121d8c8b5f66b6da3cac24bc5784553cacb6faaf678f66bc88c6615b42af2825230e - languageName: node - linkType: hard - -"is-stream@npm:^2.0.0, is-stream@npm:^2.0.1": +"is-stream@npm:^2.0.0": version: 2.0.1 resolution: "is-stream@npm:2.0.1" checksum: 10/b8e05ccdf96ac330ea83c12450304d4a591f9958c11fd17bed240af8d5ffe08aedafa4c0f4cfccd4d28dc9d4d129daca1023633d5c11601a6cbc77521f6fae66 languageName: node linkType: hard -"is-string@npm:^1.0.7, is-string@npm:^1.1.1": - version: 1.1.1 - resolution: "is-string@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.2" - checksum: 10/5277cb9e225a7cc8a368a72623b44a99f2cfa139659c6b203553540681ad4276bfc078420767aad0e73eef5f0bd07d4abf39a35d37ec216917879d11cebc1f8b - languageName: node - linkType: hard - -"is-symbol@npm:^1.0.4, is-symbol@npm:^1.1.1": - version: 1.1.1 - resolution: "is-symbol@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.2" - has-symbols: "npm:^1.1.0" - safe-regex-test: "npm:^1.1.0" - checksum: 10/db495c0d8cd0a7a66b4f4ef7fccee3ab5bd954cb63396e8ac4d32efe0e9b12fdfceb851d6c501216a71f4f21e5ff20fc2ee845a3d52d455e021c466ac5eb2db2 - languageName: node - linkType: hard - -"is-typed-array@npm:^1.1.13, is-typed-array@npm:^1.1.14, is-typed-array@npm:^1.1.15": - version: 1.1.15 - resolution: "is-typed-array@npm:1.1.15" - dependencies: - which-typed-array: "npm:^1.1.16" - checksum: 10/e8cf60b9ea85667097a6ad68c209c9722cfe8c8edf04d6218366469e51944c5cc25bae45ffb845c23f811d262e4314d3b0168748eb16711aa34d12724cdf0735 - languageName: node - linkType: hard - -"is-weakmap@npm:^2.0.2": - version: 2.0.2 - resolution: "is-weakmap@npm:2.0.2" - checksum: 10/a7b7e23206c542dcf2fa0abc483142731788771527e90e7e24f658c0833a0d91948a4f7b30d78f7a65255a48512e41a0288b778ba7fc396137515c12e201fd11 - languageName: node - linkType: hard - -"is-weakref@npm:^1.0.2, is-weakref@npm:^1.1.0": - version: 1.1.1 - resolution: "is-weakref@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - checksum: 10/543506fd8259038b371bb083aac25b16cb4fd8b12fc58053aa3d45ac28dfd001cd5c6dffbba7aeea4213c74732d46b6cb2cfb5b412eed11f2db524f3f97d09a0 - languageName: node - linkType: hard - -"is-weakset@npm:^2.0.3": - version: 2.0.4 - resolution: "is-weakset@npm:2.0.4" - dependencies: - call-bound: "npm:^1.0.3" - get-intrinsic: "npm:^1.2.6" - checksum: 10/1d5e1d0179beeed3661125a6faa2e59bfb48afda06fc70db807f178aa0ebebc3758fb6358d76b3d528090d5ef85148c345dcfbf90839592fe293e3e5e82f2134 - languageName: node - linkType: hard - -"is-what@npm:^4.1.8": - version: 4.1.16 - resolution: "is-what@npm:4.1.16" - checksum: 10/f6400634bae77be6903365dc53817292e1c4d8db1b467515d0c842505b8388ee8e558326d5e6952cb2a9d74116eca2af0c6adb8aa7e9d5c845a130ce9328bf13 - languageName: node - linkType: hard - -"is-wsl@npm:^2.2.0": - version: 2.2.0 - resolution: "is-wsl@npm:2.2.0" - dependencies: - is-docker: "npm:^2.0.0" - checksum: 10/20849846ae414997d290b75e16868e5261e86ff5047f104027026fd61d8b5a9b0b3ade16239f35e1a067b3c7cc02f70183cb661010ed16f4b6c7c93dad1b19d8 - languageName: node - linkType: hard - -"isarray@npm:^2.0.5": - version: 2.0.5 - resolution: "isarray@npm:2.0.5" - checksum: 10/1d8bc7911e13bb9f105b1b3e0b396c787a9e63046af0b8fe0ab1414488ab06b2b099b87a2d8a9e31d21c9a6fad773c7fc8b257c4880f2d957274479d28ca3414 - languageName: node - linkType: hard - -"isarray@npm:~1.0.0": - version: 1.0.0 - resolution: "isarray@npm:1.0.0" - checksum: 10/f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab - languageName: node - linkType: hard - "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -4308,15 +2452,6 @@ __metadata: languageName: node linkType: hard -"isomorphic-ws@npm:^5.0.0": - version: 5.0.0 - resolution: "isomorphic-ws@npm:5.0.0" - peerDependencies: - ws: "*" - checksum: 10/e20eb2aee09ba96247465fda40c6d22c1153394c0144fa34fe6609f341af4c8c564f60ea3ba762335a7a9c306809349f9b863c8beedf2beea09b299834ad5398 - languageName: node - linkType: hard - "istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": version: 3.2.2 resolution: "istanbul-lib-coverage@npm:3.2.2" @@ -4577,15 +2712,6 @@ __metadata: languageName: node linkType: hard -"jest-gh-md-reporter@npm:^0.0.2": - version: 0.0.2 - resolution: "jest-gh-md-reporter@npm:0.0.2" - dependencies: - ejs: "npm:^3.1.7" - checksum: 10/e61e63807a124184aeacef13816c313e8f2211aecd31974cc14f7d0dc65819286fc63969fd8e215504e2be7a3a5946fd023a231aca1d4981af14238c7dc41a7b - languageName: node - linkType: hard - "jest-haste-map@npm:^29.7.0": version: 29.7.0 resolution: "jest-haste-map@npm:29.7.0" @@ -4609,28 +2735,6 @@ __metadata: languageName: node linkType: hard -"jest-html-reporters@npm:^3.1.4": - version: 3.1.7 - resolution: "jest-html-reporters@npm:3.1.7" - dependencies: - fs-extra: "npm:^10.0.0" - open: "npm:^8.0.3" - checksum: 10/4aa780dd8cae9065e11fe0e5abb6e339eb9001f1745761a90f2e984b2dd7cf575be5cb5fef862e314b108d1602234de8ad5cf81aaf6142cf0b4eb3adc7797509 - languageName: node - linkType: hard - -"jest-junit@npm:^16.0.0": - version: 16.0.0 - resolution: "jest-junit@npm:16.0.0" - dependencies: - mkdirp: "npm:^1.0.4" - strip-ansi: "npm:^6.0.1" - uuid: "npm:^8.3.2" - xml: "npm:^1.0.1" - checksum: 10/2c33ee8bfd0c83b9aa1f8ba5905084890d5f519d294ccc2829d778ac860d5adffffec75d930f44f1d498aa8370c783e0aa6a632d947fb7e81205f0e7b926669d - languageName: node - linkType: hard - "jest-leak-detector@npm:^29.7.0": version: 29.7.0 resolution: "jest-leak-detector@npm:29.7.0" @@ -4889,14 +2993,7 @@ __metadata: languageName: node linkType: hard -"joycon@npm:^3.1.1": - version: 3.1.1 - resolution: "joycon@npm:3.1.1" - checksum: 10/4b36e3479144ec196425f46b3618f8a96ce7e1b658f091a309cd4906215f5b7a402d7df331a3e0a09681381a658d0c5f039cb3cf6907e0a1e17ed847f5d37775 - languageName: node - linkType: hard - -"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": +"js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" checksum: 10/af37d0d913fb56aec6dc0074c163cc71cd23c0b8aad5c2350747b6721d37ba118af35abdd8b33c47ec2800de07dedb16a527ca9c530ee004093e04958bd0cbf2 @@ -4970,17 +3067,6 @@ __metadata: languageName: node linkType: hard -"json5@npm:^1.0.2": - version: 1.0.2 - resolution: "json5@npm:1.0.2" - dependencies: - minimist: "npm:^1.2.0" - bin: - json5: lib/cli.js - checksum: 10/a78d812dbbd5642c4f637dd130954acfd231b074965871c3e28a5bbd571f099d623ecf9161f1960c4ddf68e0cc98dee8bebfdb94a71ad4551f85a1afc94b63f6 - languageName: node - linkType: hard - "json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" @@ -4990,19 +3076,6 @@ __metadata: languageName: node linkType: hard -"jsonfile@npm:^6.0.1": - version: 6.1.0 - resolution: "jsonfile@npm:6.1.0" - dependencies: - graceful-fs: "npm:^4.1.6" - universalify: "npm:^2.0.0" - dependenciesMeta: - graceful-fs: - optional: true - checksum: 10/03014769e7dc77d4cf05fa0b534907270b60890085dd5e4d60a382ff09328580651da0b8b4cdf44d91e4c8ae64d91791d965f05707beff000ed494a38b6fec85 - languageName: node - linkType: hard - "keyv@npm:^4.5.3": version: 4.5.4 resolution: "keyv@npm:4.5.4" @@ -5019,43 +3092,6 @@ __metadata: languageName: node linkType: hard -"lazystream@npm:^1.0.0": - version: 1.0.1 - resolution: "lazystream@npm:1.0.1" - dependencies: - readable-stream: "npm:^2.0.5" - checksum: 10/35f8cf8b5799c76570b211b079d4d706a20cbf13a4936d44cc7dbdacab1de6b346ab339ed3e3805f4693155ee5bbebbda4050fa2b666d61956e89a573089e3d4 - languageName: node - linkType: hard - -"level-supports@npm:^4.0.0": - version: 4.0.1 - resolution: "level-supports@npm:4.0.1" - checksum: 10/e2f177af813a25af29d15406a14240e2e10e5efb1c35b03643c885ac5931af760b9337826506b6395f98cf6b1e68ba294bfc345a248a1ae3f9c69e08e81824b2 - languageName: node - linkType: hard - -"level-transcoder@npm:^1.0.1": - version: 1.0.1 - resolution: "level-transcoder@npm:1.0.1" - dependencies: - buffer: "npm:^6.0.3" - module-error: "npm:^1.0.1" - checksum: 10/2fb41a1d8037fc279f851ead8cdc3852b738f1f935ac2895183cd606aae3e57008e085c7c2bd2b2d43cfd057333108cfaed604092e173ac2abdf5ab1b8333f9e - languageName: node - linkType: hard - -"level@npm:^8.0.0": - version: 8.0.1 - resolution: "level@npm:8.0.1" - dependencies: - abstract-level: "npm:^1.0.4" - browser-level: "npm:^1.0.1" - classic-level: "npm:^1.2.0" - checksum: 10/a9c6d1fc50e30b2cc80b3c975b34de0eb12daab7fb4f8a546a28303705a45685340a904544fcd32e9a380fae7c62474ebd9cdb0108021ddbc7b88dd9c913f126 - languageName: node - linkType: hard - "leven@npm:^3.1.0": version: 3.1.0 resolution: "leven@npm:3.1.0" @@ -5112,24 +3148,6 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.15, lodash@npm:^4.17.21": - version: 4.17.21 - resolution: "lodash@npm:4.17.21" - checksum: 10/c08619c038846ea6ac754abd6dd29d2568aa705feb69339e836dfa8d8b09abbb2f859371e86863eda41848221f9af43714491467b5b0299122431e202bb0c532 - languageName: node - linkType: hard - -"loose-envify@npm:^1.4.0": - version: 1.4.0 - resolution: "loose-envify@npm:1.4.0" - dependencies: - js-tokens: "npm:^3.0.0 || ^4.0.0" - bin: - loose-envify: cli.js - checksum: 10/6517e24e0cad87ec9888f500c5b5947032cdfe6ef65e1c1936a0c48a524b81e65542c9c3edc91c97d5bddc806ee2a985dbc79be89215d613b1de5db6d1cfe6f4 - languageName: node - linkType: hard - "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" @@ -5190,13 +3208,6 @@ __metadata: languageName: node linkType: hard -"math-intrinsics@npm:^1.1.0": - version: 1.1.0 - resolution: "math-intrinsics@npm:1.1.0" - checksum: 10/11df2eda46d092a6035479632e1ec865b8134bdfc4bd9e571a656f4191525404f13a283a515938c3a8de934dbfd9c09674d9da9fa831e6eb7e22b50b197d2edd - languageName: node - linkType: hard - "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" @@ -5204,14 +3215,7 @@ __metadata: languageName: node linkType: hard -"merge2@npm:^1.3.0, merge2@npm:^1.4.1": - version: 1.4.1 - resolution: "merge2@npm:1.4.1" - checksum: 10/7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 - languageName: node - linkType: hard - -"micromatch@npm:^4.0.4, micromatch@npm:^4.0.8": +"micromatch@npm:^4.0.4": version: 4.0.8 resolution: "micromatch@npm:4.0.8" dependencies: @@ -5228,15 +3232,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:9.0.3": - version: 9.0.3 - resolution: "minimatch@npm:9.0.3" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10/c81b47d28153e77521877649f4bab48348d10938df9e8147a58111fe00ef89559a2938de9f6632910c4f7bf7bb5cd81191a546167e58d357f0cfb1e18cecc1c5 - languageName: node - linkType: hard - "minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -5246,7 +3241,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^5.0.1, minimatch@npm:^5.1.0": +"minimatch@npm:^5.0.1": version: 5.1.6 resolution: "minimatch@npm:5.1.6" dependencies: @@ -5264,13 +3259,6 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.6": - version: 1.2.8 - resolution: "minimist@npm:1.2.8" - checksum: 10/908491b6cc15a6c440ba5b22780a0ba89b9810e1aea684e253e43c4e3b8d56ec1dcdd7ea96dde119c29df59c936cde16062159eae4225c691e19c70b432b6e6f - languageName: node - linkType: hard - "minipass-collect@npm:^2.0.1": version: 2.0.1 resolution: "minipass-collect@npm:2.0.1" @@ -5348,22 +3336,6 @@ __metadata: languageName: node linkType: hard -"mkdirp-classic@npm:^0.5.2": - version: 0.5.3 - resolution: "mkdirp-classic@npm:0.5.3" - checksum: 10/3f4e088208270bbcc148d53b73e9a5bd9eef05ad2cbf3b3d0ff8795278d50dd1d11a8ef1875ff5aea3fa888931f95bfcb2ad5b7c1061cfefd6284d199e6776ac - languageName: node - linkType: hard - -"mkdirp@npm:^1.0.4": - version: 1.0.4 - resolution: "mkdirp@npm:1.0.4" - bin: - mkdirp: bin/cmd.js - checksum: 10/d71b8dcd4b5af2fe13ecf3bd24070263489404fe216488c5ba7e38ece1f54daf219e72a833a3a2dc404331e870e9f44963a33399589490956bff003a3404d3b2 - languageName: node - linkType: hard - "mkdirp@npm:^3.0.1": version: 3.0.1 resolution: "mkdirp@npm:3.0.1" @@ -5373,90 +3345,24 @@ __metadata: languageName: node linkType: hard -"module-error@npm:^1.0.1, module-error@npm:^1.0.2": - version: 1.0.2 - resolution: "module-error@npm:1.0.2" - checksum: 10/5d653e35bd55b3e95f8aee2cdac108082ea892e71b8f651be92cde43e4ee86abee4fa8bd7fc3fe5e68b63926d42f63c54cd17b87a560c31f18739295575a3962 - languageName: node - linkType: hard - -"ms@npm:^2.1.1, ms@npm:^2.1.3": +"ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" - checksum: 10/aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d - languageName: node - linkType: hard - -"nan@npm:^2.19.0, nan@npm:^2.20.0": - version: 2.22.2 - resolution: "nan@npm:2.22.2" - dependencies: - node-gyp: "npm:latest" - checksum: 10/bee49de633650213970596ffbdf036bfe2109ff283a40f7742c3aa6d1fc15b9836f62bfee82192b879f56ab5f9fa9a1e5c58a908a50e5c87d91fb2118ef70827 - languageName: node - linkType: hard - -"napi-macros@npm:^2.2.2": - version: 2.2.2 - resolution: "napi-macros@npm:2.2.2" - checksum: 10/2cdb9c40ad4b424b14fbe5e13c5329559e2b511665acf41cdcda172fd2270202dc747a2d288b687c72bc70f654c797bc24a93adb67631128d62461588d7cc070 - languageName: node - linkType: hard - -"natural-compare@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare@npm:1.4.0" - checksum: 10/23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d - languageName: node - linkType: hard - -"negotiator@npm:^1.0.0": - version: 1.0.0 - resolution: "negotiator@npm:1.0.0" - checksum: 10/b5734e87295324fabf868e36fb97c84b7d7f3156ec5f4ee5bf6e488079c11054f818290fc33804cef7b1ee21f55eeb14caea83e7dafae6492a409b3e573153e5 - languageName: node - linkType: hard - -"node-domexception@npm:^1.0.0": - version: 1.0.0 - resolution: "node-domexception@npm:1.0.0" - checksum: 10/e332522f242348c511640c25a6fc7da4f30e09e580c70c6b13cb0be83c78c3e71c8d4665af2527e869fc96848924a4316ae7ec9014c091e2156f41739d4fa233 - languageName: node - linkType: hard - -"node-fetch@npm:3.3.2": - version: 3.3.2 - resolution: "node-fetch@npm:3.3.2" - dependencies: - data-uri-to-buffer: "npm:^4.0.0" - fetch-blob: "npm:^3.1.4" - formdata-polyfill: "npm:^4.0.10" - checksum: 10/24207ca8c81231c7c59151840e3fded461d67a31cf3e3b3968e12201a42f89ce4a0b5fb7079b1fa0a4655957b1ca9257553200f03a9f668b45ebad265ca5593d - languageName: node - linkType: hard - -"node-fetch@npm:^2.7.0": - version: 2.7.0 - resolution: "node-fetch@npm:2.7.0" - dependencies: - whatwg-url: "npm:^5.0.0" - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - checksum: 10/b24f8a3dc937f388192e59bcf9d0857d7b6940a2496f328381641cb616efccc9866e89ec43f2ec956bbd6c3d3ee05524ce77fe7b29ccd34692b3a16f237d6676 + checksum: 10/aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d languageName: node linkType: hard -"node-gyp-build@npm:^4.3.0": - version: 4.8.4 - resolution: "node-gyp-build@npm:4.8.4" - bin: - node-gyp-build: bin.js - node-gyp-build-optional: optional.js - node-gyp-build-test: build-test.js - checksum: 10/6a7d62289d1afc419fc8fc9bd00aa4e554369e50ca0acbc215cb91446148b75ff7e2a3b53c2c5b2c09a39d416d69f3d3237937860373104b5fe429bf30ad9ac5 +"natural-compare@npm:^1.4.0": + version: 1.4.0 + resolution: "natural-compare@npm:1.4.0" + checksum: 10/23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d + languageName: node + linkType: hard + +"negotiator@npm:^1.0.0": + version: 1.0.0 + resolution: "negotiator@npm:1.0.0" + checksum: 10/b5734e87295324fabf868e36fb97c84b7d7f3156ec5f4ee5bf6e488079c11054f818290fc33804cef7b1ee21f55eeb14caea83e7dafae6492a409b3e573153e5 languageName: node linkType: hard @@ -5521,84 +3427,14 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4.1.1": - version: 4.1.1 - resolution: "object-assign@npm:4.1.1" - checksum: 10/fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f - languageName: node - linkType: hard - -"object-inspect@npm:^1.12.3, object-inspect@npm:^1.13.3": +"object-inspect@npm:^1.12.3": version: 1.13.4 resolution: "object-inspect@npm:1.13.4" checksum: 10/aa13b1190ad3e366f6c83ad8a16ed37a19ed57d267385aa4bfdccda833d7b90465c057ff6c55d035a6b2e52c1a2295582b294217a0a3a1ae7abdd6877ef781fb languageName: node linkType: hard -"object-keys@npm:^1.1.1": - version: 1.1.1 - resolution: "object-keys@npm:1.1.1" - checksum: 10/3d81d02674115973df0b7117628ea4110d56042e5326413e4b4313f0bcdf7dd78d4a3acef2c831463fa3796a66762c49daef306f4a0ea1af44877d7086d73bde - languageName: node - linkType: hard - -"object.assign@npm:^4.1.7": - version: 4.1.7 - resolution: "object.assign@npm:4.1.7" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - has-symbols: "npm:^1.1.0" - object-keys: "npm:^1.1.1" - checksum: 10/3fe28cdd779f2a728a9a66bd688679ba231a2b16646cd1e46b528fe7c947494387dda4bc189eff3417f3717ef4f0a8f2439347cf9a9aa3cef722fbfd9f615587 - languageName: node - linkType: hard - -"object.fromentries@npm:^2.0.8": - version: 2.0.8 - resolution: "object.fromentries@npm:2.0.8" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - es-object-atoms: "npm:^1.0.0" - checksum: 10/5b2e80f7af1778b885e3d06aeb335dcc86965e39464671adb7167ab06ac3b0f5dd2e637a90d8ebd7426d69c6f135a4753ba3dd7d0fe2a7030cf718dcb910fd92 - languageName: node - linkType: hard - -"object.groupby@npm:^1.0.3": - version: 1.0.3 - resolution: "object.groupby@npm:1.0.3" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - checksum: 10/44cb86dd2c660434be65f7585c54b62f0425b0c96b5c948d2756be253ef06737da7e68d7106e35506ce4a44d16aa85a413d11c5034eb7ce5579ec28752eb42d0 - languageName: node - linkType: hard - -"object.values@npm:^1.2.0": - version: 1.2.1 - resolution: "object.values@npm:1.2.1" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10/f5ec9eccdefeaaa834b089c525663436812a65ff13de7964a1c3a9110f32054f2d58aa476a645bb14f75a79f3fe1154fb3e7bfdae7ac1e80affe171b2ef74bce - languageName: node - linkType: hard - -"on-exit-leak-free@npm:^2.1.0": - version: 2.1.2 - resolution: "on-exit-leak-free@npm:2.1.2" - checksum: 10/f7b4b7200026a08f6e4a17ba6d72e6c5cbb41789ed9cf7deaf9d9e322872c7dc5a7898549a894651ee0ee9ae635d34a678115bf8acdfba8ebd2ba2af688b563c - languageName: node - linkType: hard - -"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": +"once@npm:^1.3.0": version: 1.4.0 resolution: "once@npm:1.4.0" dependencies: @@ -5616,29 +3452,6 @@ __metadata: languageName: node linkType: hard -"open@npm:^8.0.3": - version: 8.4.2 - resolution: "open@npm:8.4.2" - dependencies: - define-lazy-prop: "npm:^2.0.0" - is-docker: "npm:^2.1.1" - is-wsl: "npm:^2.2.0" - checksum: 10/acd81a1d19879c818acb3af2d2e8e9d81d17b5367561e623248133deb7dd3aefaed527531df2677d3e6aaf0199f84df57b6b2262babff8bf46ea0029aac536c9 - languageName: node - linkType: hard - -"optimism@npm:^0.18.0": - version: 0.18.1 - resolution: "optimism@npm:0.18.1" - dependencies: - "@wry/caches": "npm:^1.0.0" - "@wry/context": "npm:^0.7.0" - "@wry/trie": "npm:^0.5.0" - tslib: "npm:^2.3.0" - checksum: 10/d805f5995d61a417d4fd49a923749db1aa310d1ae8de084ec3a5f589f8b185d9a41b7b4422d33ee75ce43115c264e14bca086f8be2bb182c76448ad08997213a - languageName: node - linkType: hard - "optionator@npm:^0.9.3": version: 0.9.4 resolution: "optionator@npm:0.9.4" @@ -5653,17 +3466,6 @@ __metadata: languageName: node linkType: hard -"own-keys@npm:^1.0.1": - version: 1.0.1 - resolution: "own-keys@npm:1.0.1" - dependencies: - get-intrinsic: "npm:^1.2.6" - object-keys: "npm:^1.1.1" - safe-push-apply: "npm:^1.0.0" - checksum: 10/ab4bb3b8636908554fc19bf899e225444195092864cb61503a0d048fdaf662b04be2605b636a4ffeaf6e8811f6fcfa8cbb210ec964c0eb1a41eb853e1d5d2f41 - languageName: node - linkType: hard - "p-limit@npm:^2.2.0": version: 2.3.0 resolution: "p-limit@npm:2.3.0" @@ -5780,13 +3582,6 @@ __metadata: languageName: node linkType: hard -"path-type@npm:^4.0.0": - version: 4.0.0 - resolution: "path-type@npm:4.0.0" - checksum: 10/5b1e2daa247062061325b8fdbfd1fb56dde0a448fb1455453276ea18c60685bdad23a445dc148cf87bc216be1573357509b7d4060494a6fd768c7efad833ee45 - languageName: node - linkType: hard - "picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" @@ -5801,68 +3596,6 @@ __metadata: languageName: node linkType: hard -"pino-abstract-transport@npm:^1.0.0, pino-abstract-transport@npm:^1.2.0": - version: 1.2.0 - resolution: "pino-abstract-transport@npm:1.2.0" - dependencies: - readable-stream: "npm:^4.0.0" - split2: "npm:^4.0.0" - checksum: 10/6ec1d19a7ff3347fd21576f744c31c3e38ca4463ae638818408f43698c936f96be6a0bc750af5f7c1ae81873183bfcb062b7a0d12dc159a1813ea900c388c693 - languageName: node - linkType: hard - -"pino-pretty@npm:^10.2.3": - version: 10.3.1 - resolution: "pino-pretty@npm:10.3.1" - dependencies: - colorette: "npm:^2.0.7" - dateformat: "npm:^4.6.3" - fast-copy: "npm:^3.0.0" - fast-safe-stringify: "npm:^2.1.1" - help-me: "npm:^5.0.0" - joycon: "npm:^3.1.1" - minimist: "npm:^1.2.6" - on-exit-leak-free: "npm:^2.1.0" - pino-abstract-transport: "npm:^1.0.0" - pump: "npm:^3.0.0" - readable-stream: "npm:^4.0.0" - secure-json-parse: "npm:^2.4.0" - sonic-boom: "npm:^3.0.0" - strip-json-comments: "npm:^3.1.1" - bin: - pino-pretty: bin.js - checksum: 10/4284f125f7e8a5a10e856c8fd591ba34c30c0a0071a0b265a9eda43c3e447ba11d40b06cc67108675586358a5d1213a6ac3a92f6abd2896abfbab9a5b4c17072 - languageName: node - linkType: hard - -"pino-std-serializers@npm:^6.0.0": - version: 6.2.2 - resolution: "pino-std-serializers@npm:6.2.2" - checksum: 10/a00cdff4e1fbc206da9bed047e6dc400b065f43e8b4cef1635b0192feab0e8f932cdeb0faaa38a5d93d2e777ba4cda939c2ed4c1a70f6839ff25f9aef97c27ff - languageName: node - linkType: hard - -"pino@npm:^8.16.0": - version: 8.21.0 - resolution: "pino@npm:8.21.0" - dependencies: - atomic-sleep: "npm:^1.0.0" - fast-redact: "npm:^3.1.1" - on-exit-leak-free: "npm:^2.1.0" - pino-abstract-transport: "npm:^1.2.0" - pino-std-serializers: "npm:^6.0.0" - process-warning: "npm:^3.0.0" - quick-format-unescaped: "npm:^4.0.3" - real-require: "npm:^0.2.0" - safe-stable-stringify: "npm:^2.3.1" - sonic-boom: "npm:^3.7.0" - thread-stream: "npm:^2.6.0" - bin: - pino: bin.js - checksum: 10/5a054eab533ab91b20f63497b86070f0a6b40e4688cde9de66d23e03d6046c4e95d69c3f526dea9f30bcbc5874c7fbf0f91660cded4753946fd02261ca8ac340 - languageName: node - linkType: hard - "pirates@npm:^4.0.4": version: 4.0.6 resolution: "pirates@npm:4.0.6" @@ -5879,13 +3612,6 @@ __metadata: languageName: node linkType: hard -"possible-typed-array-names@npm:^1.0.0": - version: 1.1.0 - resolution: "possible-typed-array-names@npm:1.1.0" - checksum: 10/2f44137b8d3dd35f4a7ba7469eec1cd9cfbb46ec164b93a5bc1f4c3d68599c9910ee3b91da1d28b4560e9cc8414c3cd56fedc07259c67e52cc774476270d3302 - languageName: node - linkType: hard - "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" @@ -5893,24 +3619,6 @@ __metadata: languageName: node linkType: hard -"prettier-linter-helpers@npm:^1.0.0": - version: 1.0.0 - resolution: "prettier-linter-helpers@npm:1.0.0" - dependencies: - fast-diff: "npm:^1.1.2" - checksum: 10/00ce8011cf6430158d27f9c92cfea0a7699405633f7f1d4a45f07e21bf78e99895911cbcdc3853db3a824201a7c745bd49bfea8abd5fb9883e765a90f74f8392 - languageName: node - linkType: hard - -"prettier@npm:^3.0.3": - version: 3.5.2 - resolution: "prettier@npm:3.5.2" - bin: - prettier: bin/prettier.cjs - checksum: 10/ac7a157c8ec76459b13d81a03ff65d228015992cb926b676b0f1c83edd47e5db8ba257336b400be20942fc671816f1afde377cffe94d9e4368762a3d3acbffe5 - languageName: node - linkType: hard - "pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": version: 29.7.0 resolution: "pretty-format@npm:29.7.0" @@ -5929,27 +3637,6 @@ __metadata: languageName: node linkType: hard -"process-nextick-args@npm:~2.0.0": - version: 2.0.1 - resolution: "process-nextick-args@npm:2.0.1" - checksum: 10/1d38588e520dab7cea67cbbe2efdd86a10cc7a074c09657635e34f035277b59fbb57d09d8638346bf7090f8e8ebc070c96fa5fd183b777fff4f5edff5e9466cf - languageName: node - linkType: hard - -"process-warning@npm:^3.0.0": - version: 3.0.0 - resolution: "process-warning@npm:3.0.0" - checksum: 10/2d82fa641e50a5789eaf0f2b33453760996e373d4591aac576a22d696186ab7e240a0592db86c264d4f28a46c2abbe9b94689752017db7dadc90f169f12b0924 - languageName: node - linkType: hard - -"process@npm:^0.11.10": - version: 0.11.10 - resolution: "process@npm:0.11.10" - checksum: 10/dbaa7e8d1d5cf375c36963ff43116772a989ef2bb47c9bdee20f38fd8fc061119cf38140631cf90c781aca4d3f0f0d2c834711952b728953f04fd7d238f59f5b - languageName: node - linkType: hard - "promise-retry@npm:^2.0.1": version: 2.0.1 resolution: "promise-retry@npm:2.0.1" @@ -5970,47 +3657,6 @@ __metadata: languageName: node linkType: hard -"prop-types@npm:^15.7.2": - version: 15.8.1 - resolution: "prop-types@npm:15.8.1" - dependencies: - loose-envify: "npm:^1.4.0" - object-assign: "npm:^4.1.1" - react-is: "npm:^16.13.1" - checksum: 10/7d959caec002bc964c86cdc461ec93108b27337dabe6192fb97d69e16a0c799a03462713868b40749bfc1caf5f57ef80ac3e4ffad3effa636ee667582a75e2c0 - languageName: node - linkType: hard - -"proper-lockfile@npm:^4.1.2": - version: 4.1.2 - resolution: "proper-lockfile@npm:4.1.2" - dependencies: - graceful-fs: "npm:^4.2.4" - retry: "npm:^0.12.0" - signal-exit: "npm:^3.0.2" - checksum: 10/000a4875f543f591872b36ca94531af8a6463ddb0174f41c0b004d19e231d7445268b422ff1ea595e43d238655c702250cd3d27f408e7b9d97b56f1533ba26bf - languageName: node - linkType: hard - -"properties-reader@npm:^2.3.0": - version: 2.3.0 - resolution: "properties-reader@npm:2.3.0" - dependencies: - mkdirp: "npm:^1.0.4" - checksum: 10/0b41eb4136dc278ae0d97968ccce8de2d48d321655b319192e31f2424f1c6e052182204671e65aa8967216360cb3e7cbd9129830062e058fe9d6a1d74964c29a - languageName: node - linkType: hard - -"pump@npm:^3.0.0": - version: 3.0.2 - resolution: "pump@npm:3.0.2" - dependencies: - end-of-stream: "npm:^1.1.0" - once: "npm:^1.3.1" - checksum: 10/e0c4216874b96bd25ddf31a0b61a5613e26cc7afa32379217cf39d3915b0509def3565f5f6968fafdad2894c8bbdbd67d340e84f3634b2a29b950cffb6442d9f - languageName: node - linkType: hard - "punycode@npm:^2.1.0": version: 2.3.1 resolution: "punycode@npm:2.3.1" @@ -6025,27 +3671,13 @@ __metadata: languageName: node linkType: hard -"queue-microtask@npm:^1.2.2, queue-microtask@npm:^1.2.3": +"queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" checksum: 10/72900df0616e473e824202113c3df6abae59150dfb73ed13273503127235320e9c8ca4aaaaccfd58cf417c6ca92a6e68ee9a5c3182886ae949a768639b388a7b languageName: node linkType: hard -"quick-format-unescaped@npm:^4.0.3": - version: 4.0.4 - resolution: "quick-format-unescaped@npm:4.0.4" - checksum: 10/591eca457509a99368b623db05248c1193aa3cedafc9a077d7acab09495db1231017ba3ad1b5386e5633271edd0a03b312d8640a59ee585b8516a42e15438aa7 - languageName: node - linkType: hard - -"react-is@npm:^16.13.1, react-is@npm:^16.7.0": - version: 16.13.1 - resolution: "react-is@npm:16.13.1" - checksum: 10/5aa564a1cde7d391ac980bedee21202fc90bdea3b399952117f54fb71a932af1e5902020144fb354b4690b2414a0c7aafe798eb617b76a3d441d956db7726fdf - languageName: node - linkType: hard - "react-is@npm:^18.0.0": version: 18.3.1 resolution: "react-is@npm:18.3.1" @@ -6053,106 +3685,6 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.0.5": - version: 2.3.8 - resolution: "readable-stream@npm:2.3.8" - dependencies: - core-util-is: "npm:~1.0.0" - inherits: "npm:~2.0.3" - isarray: "npm:~1.0.0" - process-nextick-args: "npm:~2.0.0" - safe-buffer: "npm:~5.1.1" - string_decoder: "npm:~1.1.1" - util-deprecate: "npm:~1.0.1" - checksum: 10/8500dd3a90e391d6c5d889256d50ec6026c059fadee98ae9aa9b86757d60ac46fff24fafb7a39fa41d54cb39d8be56cc77be202ebd4cd8ffcf4cb226cbaa40d4 - languageName: node - linkType: hard - -"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0": - version: 3.6.2 - resolution: "readable-stream@npm:3.6.2" - dependencies: - inherits: "npm:^2.0.3" - string_decoder: "npm:^1.1.1" - util-deprecate: "npm:^1.0.1" - checksum: 10/d9e3e53193adcdb79d8f10f2a1f6989bd4389f5936c6f8b870e77570853561c362bee69feca2bbb7b32368ce96a85504aa4cedf7cf80f36e6a9de30d64244048 - languageName: node - linkType: hard - -"readable-stream@npm:^4.0.0": - version: 4.7.0 - resolution: "readable-stream@npm:4.7.0" - dependencies: - abort-controller: "npm:^3.0.0" - buffer: "npm:^6.0.3" - events: "npm:^3.3.0" - process: "npm:^0.11.10" - string_decoder: "npm:^1.3.0" - checksum: 10/bdf096c8ff59452ce5d08f13da9597f9fcfe400b4facfaa88e74ec057e5ad1fdfa140ffe28e5ed806cf4d2055f0b812806e962bca91dce31bc4cef08e53be3a4 - languageName: node - linkType: hard - -"readdir-glob@npm:^1.1.2": - version: 1.1.3 - resolution: "readdir-glob@npm:1.1.3" - dependencies: - minimatch: "npm:^5.1.0" - checksum: 10/ca3a20aa1e715d671302d4ec785a32bf08e59d6d0dd25d5fc03e9e5a39f8c612cdf809ab3e638a79973db7ad6868492edf38504701e313328e767693671447d6 - languageName: node - linkType: hard - -"real-require@npm:^0.2.0": - version: 0.2.0 - resolution: "real-require@npm:0.2.0" - checksum: 10/ddf44ee76301c774e9c9f2826da8a3c5c9f8fc87310f4a364e803ef003aa1a43c378b4323051ced212097fff1af459070f4499338b36a7469df1d4f7e8c0ba4c - languageName: node - linkType: hard - -"reflect.getprototypeof@npm:^1.0.6, reflect.getprototypeof@npm:^1.0.9": - version: 1.0.10 - resolution: "reflect.getprototypeof@npm:1.0.10" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.9" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.7" - get-proto: "npm:^1.0.1" - which-builtin-type: "npm:^1.2.1" - checksum: 10/80a4e2be716f4fe46a89a08ccad0863b47e8ce0f49616cab2d65dab0fbd53c6fdba0f52935fd41d37a2e4e22355c272004f920d63070de849f66eea7aeb4a081 - languageName: node - linkType: hard - -"regexp.prototype.flags@npm:^1.5.3": - version: 1.5.4 - resolution: "regexp.prototype.flags@npm:1.5.4" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-errors: "npm:^1.3.0" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - set-function-name: "npm:^2.0.2" - checksum: 10/8ab897ca445968e0b96f6237641510f3243e59c180ee2ee8d83889c52ff735dd1bf3657fcd36db053e35e1d823dd53f2565d0b8021ea282c9fe62401c6c3bd6d - languageName: node - linkType: hard - -"rehackt@npm:^0.1.0": - version: 0.1.0 - resolution: "rehackt@npm:0.1.0" - peerDependencies: - "@types/react": "*" - react: "*" - peerDependenciesMeta: - "@types/react": - optional: true - react: - optional: true - checksum: 10/c81adead82c165dffc574cbf9e1de3605522782a56b48df48b68d53d45c4d8c9253df3790109335bf97072424e54ad2423bb9544ca3a985fa91995dda43452fc - languageName: node - linkType: hard - "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" @@ -6183,13 +3715,6 @@ __metadata: languageName: node linkType: hard -"resolve-pkg-maps@npm:^1.0.0": - version: 1.0.0 - resolution: "resolve-pkg-maps@npm:1.0.0" - checksum: 10/0763150adf303040c304009231314d1e84c6e5ebfa2d82b7d94e96a6e82bacd1dcc0b58ae257315f3c8adb89a91d8d0f12928241cba2df1680fbe6f60bf99b0e - languageName: node - linkType: hard - "resolve.exports@npm:^2.0.0": version: 2.0.3 resolution: "resolve.exports@npm:2.0.3" @@ -6197,7 +3722,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.20.0, resolve@npm:^1.22.2, resolve@npm:^1.22.4": +"resolve@npm:^1.20.0": version: 1.22.10 resolution: "resolve@npm:1.22.10" dependencies: @@ -6210,7 +3735,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.2#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": +"resolve@patch:resolve@npm%3A^1.20.0#optional!builtin": version: 1.22.10 resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" dependencies: @@ -6263,59 +3788,22 @@ __metadata: version: 0.0.0-use.local resolution: "root-workspace-0b6124@workspace:." dependencies: + "@biomejs/biome": "npm:1.9.4" "@midnight-ntwrk/compact-runtime": "npm:^0.7.0" - "@midnight-ntwrk/dapp-connector-api": "npm:^1.2.2" - "@midnight-ntwrk/ledger": "npm:^3.0.2" - "@midnight-ntwrk/midnight-js-contracts": "npm:0.2.5" - "@midnight-ntwrk/midnight-js-fetch-zk-config-provider": "npm:0.2.5" - "@midnight-ntwrk/midnight-js-http-client-proof-provider": "npm:0.2.5" - "@midnight-ntwrk/midnight-js-indexer-public-data-provider": "npm:0.2.5" - "@midnight-ntwrk/midnight-js-level-private-state-provider": "npm:0.2.5" - "@midnight-ntwrk/midnight-js-network-id": "npm:0.2.5" - "@midnight-ntwrk/midnight-js-node-zk-config-provider": "npm:0.2.5" - "@midnight-ntwrk/midnight-js-types": "npm:0.2.5" - "@midnight-ntwrk/midnight-js-utils": "npm:0.2.5" - "@midnight-ntwrk/wallet": "npm:^3.7.3" - "@midnight-ntwrk/wallet-api": "npm:^3.5.0" + "@midnight-ntwrk/ledger": "npm:^3.0.6" + "@midnight-ntwrk/zswap": "npm:^3.0.6" "@types/jest": "npm:^29.5.6" "@types/node": "npm:^18.18.6" - "@typescript-eslint/eslint-plugin": "npm:^6.8.0" - "@typescript-eslint/parser": "npm:^6.8.0" - eslint: "npm:^8.52.0" - eslint-config-prettier: "npm:^9.0.0" - eslint-plugin-import: "npm:^2.28.1" - eslint-plugin-n: "npm:^16.2.0" - eslint-plugin-prettier: "npm:^5.0.1" - eslint-plugin-promise: "npm:^6.1.1" fast-check: "npm:^3.15.0" - fp-ts: "npm:^2.16.1" - io-ts: "npm:^2.2.20" jest: "npm:^29.7.0" jest-fast-check: "npm:^2.0.0" - jest-gh-md-reporter: "npm:^0.0.2" - jest-html-reporters: "npm:^3.1.4" - jest-junit: "npm:^16.0.0" - pino: "npm:^8.16.0" - pino-pretty: "npm:^10.2.3" - prettier: "npm:^3.0.3" - rxjs: "npm:^7.8.1" - testcontainers: "npm:^10.3.2" ts-jest: "npm:^29.1.1" ts-node: "npm:^10.9.1" - turbo: "npm:^1.10.16" + turbo: "npm:^2.5.1" typescript: "npm:^5.2.2" languageName: unknown linkType: soft -"run-parallel-limit@npm:^1.1.0": - version: 1.1.0 - resolution: "run-parallel-limit@npm:1.1.0" - dependencies: - queue-microtask: "npm:^1.2.2" - checksum: 10/672c3b87e7f939c684b9965222b361421db0930223ed1e43ebf0e7e48ccc1a022ea4de080bef4d5468434e2577c33b7681e3f03b7593fdc49ad250a55381123c - languageName: node - linkType: hard - "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -6325,91 +3813,13 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:^7.5, rxjs@npm:^7.5.0, rxjs@npm:^7.8.1": - version: 7.8.2 - resolution: "rxjs@npm:7.8.2" - dependencies: - tslib: "npm:^2.1.0" - checksum: 10/03dff09191356b2b87d94fbc1e97c4e9eb3c09d4452399dddd451b09c2f1ba8d56925a40af114282d7bc0c6fe7514a2236ca09f903cf70e4bbf156650dddb49d - languageName: node - linkType: hard - -"safe-array-concat@npm:^1.1.3": - version: 1.1.3 - resolution: "safe-array-concat@npm:1.1.3" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.2" - get-intrinsic: "npm:^1.2.6" - has-symbols: "npm:^1.1.0" - isarray: "npm:^2.0.5" - checksum: 10/fac4f40f20a3f7da024b54792fcc61059e814566dcbb04586bfefef4d3b942b2408933f25b7b3dd024affd3f2a6bbc916bef04807855e4f192413941369db864 - languageName: node - linkType: hard - -"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": - version: 5.1.2 - resolution: "safe-buffer@npm:5.1.2" - checksum: 10/7eb5b48f2ed9a594a4795677d5a150faa7eb54483b2318b568dc0c4fc94092a6cce5be02c7288a0500a156282f5276d5688bce7259299568d1053b2150ef374a - languageName: node - linkType: hard - -"safe-buffer@npm:~5.2.0": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: 10/32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451 - languageName: node - linkType: hard - -"safe-push-apply@npm:^1.0.0": - version: 1.0.0 - resolution: "safe-push-apply@npm:1.0.0" - dependencies: - es-errors: "npm:^1.3.0" - isarray: "npm:^2.0.5" - checksum: 10/2bd4e53b6694f7134b9cf93631480e7fafc8637165f0ee91d5a4af5e7f33d37de9562d1af5021178dd4217d0230cde8d6530fa28cfa1ebff9a431bf8fff124b4 - languageName: node - linkType: hard - -"safe-regex-test@npm:^1.1.0": - version: 1.1.0 - resolution: "safe-regex-test@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - is-regex: "npm:^1.2.1" - checksum: 10/ebdb61f305bf4756a5b023ad86067df5a11b26898573afe9e52a548a63c3bd594825d9b0e2dde2eb3c94e57e0e04ac9929d4107c394f7b8e56a4613bed46c69a - languageName: node - linkType: hard - -"safe-stable-stringify@npm:^2.3.1": - version: 2.5.0 - resolution: "safe-stable-stringify@npm:2.5.0" - checksum: 10/2697fa186c17c38c3ca5309637b4ac6de2f1c3d282da27cd5e1e3c88eca0fb1f9aea568a6aabdf284111592c8782b94ee07176f17126031be72ab1313ed46c5c - languageName: node - linkType: hard - -"safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:~2.1.0": +"safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" checksum: 10/7eaf7a0cf37cc27b42fb3ef6a9b1df6e93a1c6d98c6c6702b02fe262d5fcbd89db63320793b99b21cb5348097d0a53de81bd5f4e8b86e20cc9412e3f1cfb4e83 languageName: node linkType: hard -"scale-ts@npm:^1.1.0": - version: 1.6.1 - resolution: "scale-ts@npm:1.6.1" - checksum: 10/f1f9bf1d9abfcfcaf8ae2ae326270beca5c2456cc72f6b6b8230aa175a30bdcd6387678746a4d873c834efbba9c8e015698d42ee67bd71b70f7adfe2e0ba1d39 - languageName: node - linkType: hard - -"secure-json-parse@npm:^2.4.0": - version: 2.7.0 - resolution: "secure-json-parse@npm:2.7.0" - checksum: 10/974386587060b6fc5b1ac06481b2f9dbbb0d63c860cc73dc7533f27835fdb67b0ef08762dbfef25625c15bc0a0c366899e00076cb0d556af06b71e22f1dede4c - languageName: node - linkType: hard - "semver@npm:^6.3.0, semver@npm:^6.3.1": version: 6.3.1 resolution: "semver@npm:6.3.1" @@ -6419,117 +3829,32 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.0.0, semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.7.1": - version: 7.7.1 - resolution: "semver@npm:7.7.1" - bin: - semver: bin/semver.js - checksum: 10/4cfa1eb91ef3751e20fc52e47a935a0118d56d6f15a837ab814da0c150778ba2ca4f1a4d9068b33070ea4273629e615066664c2cfcd7c272caf7a8a0f6518b2c - languageName: node - linkType: hard - -"set-function-length@npm:^1.2.2": - version: 1.2.2 - resolution: "set-function-length@npm:1.2.2" - dependencies: - define-data-property: "npm:^1.1.4" - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - get-intrinsic: "npm:^1.2.4" - gopd: "npm:^1.0.1" - has-property-descriptors: "npm:^1.0.2" - checksum: 10/505d62b8e088468917ca4e3f8f39d0e29f9a563b97dbebf92f4bd2c3172ccfb3c5b8e4566d5fcd00784a00433900e7cb8fbc404e2dbd8c3818ba05bb9d4a8a6d - languageName: node - linkType: hard - -"set-function-name@npm:^2.0.2": - version: 2.0.2 - resolution: "set-function-name@npm:2.0.2" - dependencies: - define-data-property: "npm:^1.1.4" - es-errors: "npm:^1.3.0" - functions-have-names: "npm:^1.2.3" - has-property-descriptors: "npm:^1.0.2" - checksum: 10/c7614154a53ebf8c0428a6c40a3b0b47dac30587c1a19703d1b75f003803f73cdfa6a93474a9ba678fa565ef5fbddc2fae79bca03b7d22ab5fd5163dbe571a74 - languageName: node - linkType: hard - -"set-proto@npm:^1.0.0": - version: 1.0.0 - resolution: "set-proto@npm:1.0.0" - dependencies: - dunder-proto: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - checksum: 10/b87f8187bca595ddc3c0721ece4635015fd9d7cb294e6dd2e394ce5186a71bbfa4dc8a35010958c65e43ad83cde09642660e61a952883c24fd6b45ead15f045c - languageName: node - linkType: hard - -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: "npm:^3.0.0" - checksum: 10/6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa - languageName: node - linkType: hard - -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 10/1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 - languageName: node - linkType: hard - -"side-channel-list@npm:^1.0.0": - version: 1.0.0 - resolution: "side-channel-list@npm:1.0.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - checksum: 10/603b928997abd21c5a5f02ae6b9cc36b72e3176ad6827fab0417ead74580cc4fb4d5c7d0a8a2ff4ead34d0f9e35701ed7a41853dac8a6d1a664fcce1a044f86f - languageName: node - linkType: hard - -"side-channel-map@npm:^1.0.1": - version: 1.0.1 - resolution: "side-channel-map@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - checksum: 10/5771861f77feefe44f6195ed077a9e4f389acc188f895f570d56445e251b861754b547ea9ef73ecee4e01fdada6568bfe9020d2ec2dfc5571e9fa1bbc4a10615 +"semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.7.1": + version: 7.7.1 + resolution: "semver@npm:7.7.1" + bin: + semver: bin/semver.js + checksum: 10/4cfa1eb91ef3751e20fc52e47a935a0118d56d6f15a837ab814da0c150778ba2ca4f1a4d9068b33070ea4273629e615066664c2cfcd7c272caf7a8a0f6518b2c languageName: node linkType: hard -"side-channel-weakmap@npm:^1.0.2": - version: 1.0.2 - resolution: "side-channel-weakmap@npm:1.0.2" +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - side-channel-map: "npm:^1.0.1" - checksum: 10/a815c89bc78c5723c714ea1a77c938377ea710af20d4fb886d362b0d1f8ac73a17816a5f6640f354017d7e292a43da9c5e876c22145bac00b76cfb3468001736 + shebang-regex: "npm:^3.0.0" + checksum: 10/6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa languageName: node linkType: hard -"side-channel@npm:^1.1.0": - version: 1.1.0 - resolution: "side-channel@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - side-channel-list: "npm:^1.0.0" - side-channel-map: "npm:^1.0.1" - side-channel-weakmap: "npm:^1.0.2" - checksum: 10/7d53b9db292c6262f326b6ff3bc1611db84ece36c2c7dc0e937954c13c73185b0406c56589e2bb8d071d6fee468e14c39fb5d203ee39be66b7b8174f179afaba +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 10/1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 languageName: node linkType: hard -"signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": +"signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" checksum: 10/a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 @@ -6585,15 +3910,6 @@ __metadata: languageName: node linkType: hard -"sonic-boom@npm:^3.0.0, sonic-boom@npm:^3.7.0": - version: 3.8.1 - resolution: "sonic-boom@npm:3.8.1" - dependencies: - atomic-sleep: "npm:^1.0.0" - checksum: 10/e03c9611e43fa81132cd2ce0fe4eb7fbcf19db267e9dec20dc6c586f82465c9c906e91a02f72150c740463ad9335536ea2131850307aaa6686d1fb5d4cc4be3e - languageName: node - linkType: hard - "source-map-support@npm:0.5.13": version: 0.5.13 resolution: "source-map-support@npm:0.5.13" @@ -6611,20 +3927,6 @@ __metadata: languageName: node linkType: hard -"split-ca@npm:^1.0.1": - version: 1.0.1 - resolution: "split-ca@npm:1.0.1" - checksum: 10/1e7409938a95ee843fe2593156a5735e6ee63772748ee448ea8477a5a3e3abde193c3325b3696e56a5aff07c7dcf6b1f6a2f2a036895b4f3afe96abb366d893f - languageName: node - linkType: hard - -"split2@npm:^4.0.0": - version: 4.2.0 - resolution: "split2@npm:4.2.0" - checksum: 10/09bbefc11bcf03f044584c9764cd31a252d8e52cea29130950b26161287c11f519807c5e54bd9e5804c713b79c02cefe6a98f4688630993386be353e03f534ab - languageName: node - linkType: hard - "sprintf-js@npm:^1.1.3": version: 1.1.3 resolution: "sprintf-js@npm:1.1.3" @@ -6639,33 +3941,6 @@ __metadata: languageName: node linkType: hard -"ssh-remote-port-forward@npm:^1.0.4": - version: 1.0.4 - resolution: "ssh-remote-port-forward@npm:1.0.4" - dependencies: - "@types/ssh2": "npm:^0.5.48" - ssh2: "npm:^1.4.0" - checksum: 10/c6c04c5ddfde7cb06e9a8655a152bd28fe6771c6fe62ff0bc08be229491546c410f30b153c968b8d6817a57d38678a270c228f30143ec0fe1be546efc4f6b65a - languageName: node - linkType: hard - -"ssh2@npm:^1.11.0, ssh2@npm:^1.4.0": - version: 1.16.0 - resolution: "ssh2@npm:1.16.0" - dependencies: - asn1: "npm:^0.2.6" - bcrypt-pbkdf: "npm:^1.0.2" - cpu-features: "npm:~0.0.10" - nan: "npm:^2.20.0" - dependenciesMeta: - cpu-features: - optional: true - nan: - optional: true - checksum: 10/0951c22d9c5a0e3b89a8e5ae890ebcbce9f1f94dbed37d1490e4e48e26bc8b074fa81f202ee57b708e31b5f33033f4c870b92047f4f02b6bc26c32225b01d84c - languageName: node - linkType: hard - "ssri@npm:^12.0.0": version: 12.0.0 resolution: "ssri@npm:12.0.0" @@ -6684,20 +3959,6 @@ __metadata: languageName: node linkType: hard -"streamx@npm:^2.15.0, streamx@npm:^2.21.0": - version: 2.22.0 - resolution: "streamx@npm:2.22.0" - dependencies: - bare-events: "npm:^2.2.0" - fast-fifo: "npm:^1.3.2" - text-decoder: "npm:^1.1.0" - dependenciesMeta: - bare-events: - optional: true - checksum: 10/9c329bb316e2085e207e471ecd0da18b4ed5b1cfe5cf10e9e7fad3f8f50c6ca1a6a844bdfd9bc7521560b97f229890de82ca162a0e66115300b91a489b1cbefd - languageName: node - linkType: hard - "string-length@npm:^4.0.1": version: 4.0.2 resolution: "string-length@npm:4.0.2" @@ -6730,62 +3991,6 @@ __metadata: languageName: node linkType: hard -"string.prototype.trim@npm:^1.2.10": - version: 1.2.10 - resolution: "string.prototype.trim@npm:1.2.10" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.2" - define-data-property: "npm:^1.1.4" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-object-atoms: "npm:^1.0.0" - has-property-descriptors: "npm:^1.0.2" - checksum: 10/47bb63cd2470a64bc5e2da1e570d369c016ccaa85c918c3a8bb4ab5965120f35e66d1f85ea544496fac84b9207a6b722adf007e6c548acd0813e5f8a82f9712a - languageName: node - linkType: hard - -"string.prototype.trimend@npm:^1.0.8, string.prototype.trimend@npm:^1.0.9": - version: 1.0.9 - resolution: "string.prototype.trimend@npm:1.0.9" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.2" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10/140c73899b6747de9e499c7c2e7a83d549c47a26fa06045b69492be9cfb9e2a95187499a373983a08a115ecff8bc3bd7b0fb09b8ff72fb2172abe766849272ef - languageName: node - linkType: hard - -"string.prototype.trimstart@npm:^1.0.8": - version: 1.0.8 - resolution: "string.prototype.trimstart@npm:1.0.8" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10/160167dfbd68e6f7cb9f51a16074eebfce1571656fc31d40c3738ca9e30e35496f2c046fe57b6ad49f65f238a152be8c86fd9a2dd58682b5eba39dad995b3674 - languageName: node - linkType: hard - -"string_decoder@npm:^1.1.1, string_decoder@npm:^1.3.0": - version: 1.3.0 - resolution: "string_decoder@npm:1.3.0" - dependencies: - safe-buffer: "npm:~5.2.0" - checksum: 10/54d23f4a6acae0e93f999a585e673be9e561b65cd4cca37714af1e893ab8cd8dfa52a9e4f58f48f87b4a44918d3a9254326cb80ed194bf2e4c226e2b21767e56 - languageName: node - linkType: hard - -"string_decoder@npm:~1.1.1": - version: 1.1.1 - resolution: "string_decoder@npm:1.1.1" - dependencies: - safe-buffer: "npm:~5.1.0" - checksum: 10/7c41c17ed4dea105231f6df208002ebddd732e8e9e2d619d133cecd8e0087ddfd9587d2feb3c8caf3213cbd841ada6d057f5142cae68a4e62d3540778d9819b4 - languageName: node - linkType: hard - "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -6804,13 +4009,6 @@ __metadata: languageName: node linkType: hard -"strip-bom@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-bom@npm:3.0.0" - checksum: 10/8d50ff27b7ebe5ecc78f1fe1e00fcdff7af014e73cf724b46fb81ef889eeb1015fc5184b64e81a2efe002180f3ba431bdd77e300da5c6685d702780fbf0c8d5b - languageName: node - linkType: hard - "strip-bom@npm:^4.0.0": version: 4.0.0 resolution: "strip-bom@npm:4.0.0" @@ -6832,15 +4030,6 @@ __metadata: languageName: node linkType: hard -"superjson@npm:^1.13.1": - version: 1.13.3 - resolution: "superjson@npm:1.13.3" - dependencies: - copy-anything: "npm:^3.0.2" - checksum: 10/71a186c513a9821e58264c0563cd1b3cf07d3b5ba53a09cc5c1a604d8ffeacac976a6ba1b5d5b3c71b6ab5a1941dfba5a15e3f106ad3ef22fe8d5eee3e2be052 - languageName: node - linkType: hard - "supports-color@npm:^7.1.0": version: 7.2.0 resolution: "supports-color@npm:7.2.0" @@ -6866,76 +4055,6 @@ __metadata: languageName: node linkType: hard -"symbol-observable@npm:^4.0.0": - version: 4.0.0 - resolution: "symbol-observable@npm:4.0.0" - checksum: 10/983aef3912ad080fc834b9ad115d44bc2994074c57cea4fb008e9f7ab9bb4118b908c63d9edc861f51257bc0595025510bdf7263bb09d8953a6929f240165c24 - languageName: node - linkType: hard - -"synckit@npm:^0.9.1": - version: 0.9.2 - resolution: "synckit@npm:0.9.2" - dependencies: - "@pkgr/core": "npm:^0.1.0" - tslib: "npm:^2.6.2" - checksum: 10/d45c4288be9c0232343650643892a7edafb79152c0c08d7ae5d33ca2c296b67a0e15f8cb5c9153969612c4ea5cd5686297542384aab977db23cfa6653fe02027 - languageName: node - linkType: hard - -"tar-fs@npm:^3.0.6": - version: 3.0.8 - resolution: "tar-fs@npm:3.0.8" - dependencies: - bare-fs: "npm:^4.0.1" - bare-path: "npm:^3.0.0" - pump: "npm:^3.0.0" - tar-stream: "npm:^3.1.5" - dependenciesMeta: - bare-fs: - optional: true - bare-path: - optional: true - checksum: 10/fdcd1c66dc5e2cad5544ffe7eab9a470b419290b22300c344688df51bf06127963da07a1e3ae23cae80851cd9f60149e80b38e56485dd7a14aea701241ac2f81 - languageName: node - linkType: hard - -"tar-fs@npm:~2.0.1": - version: 2.0.1 - resolution: "tar-fs@npm:2.0.1" - dependencies: - chownr: "npm:^1.1.1" - mkdirp-classic: "npm:^0.5.2" - pump: "npm:^3.0.0" - tar-stream: "npm:^2.0.0" - checksum: 10/85ceac6fce0e9175b5b67c0eca8864b7d29a940cae8b7657c60b66e8a252319d701c3df12814162a6839e6120f9e1975757293bdeaf294ad5b15721d236c4d32 - languageName: node - linkType: hard - -"tar-stream@npm:^2.0.0": - version: 2.2.0 - resolution: "tar-stream@npm:2.2.0" - dependencies: - bl: "npm:^4.0.3" - end-of-stream: "npm:^1.4.1" - fs-constants: "npm:^1.0.0" - inherits: "npm:^2.0.3" - readable-stream: "npm:^3.1.1" - checksum: 10/1a52a51d240c118cbcd30f7368ea5e5baef1eac3e6b793fb1a41e6cd7319296c79c0264ccc5859f5294aa80f8f00b9239d519e627b9aade80038de6f966fec6a - languageName: node - linkType: hard - -"tar-stream@npm:^3.0.0, tar-stream@npm:^3.1.5": - version: 3.1.7 - resolution: "tar-stream@npm:3.1.7" - dependencies: - b4a: "npm:^1.6.4" - fast-fifo: "npm:^1.2.0" - streamx: "npm:^2.15.0" - checksum: 10/b21a82705a72792544697c410451a4846af1f744176feb0ff11a7c3dd0896961552e3def5e1c9a6bbee4f0ae298b8252a1f4c9381e9f991553b9e4847976f05c - languageName: node - linkType: hard - "tar@npm:^7.4.3": version: 7.4.3 resolution: "tar@npm:7.4.3" @@ -6961,38 +4080,6 @@ __metadata: languageName: node linkType: hard -"testcontainers@npm:^10.3.2": - version: 10.18.0 - resolution: "testcontainers@npm:10.18.0" - dependencies: - "@balena/dockerignore": "npm:^1.0.2" - "@types/dockerode": "npm:^3.3.29" - archiver: "npm:^7.0.1" - async-lock: "npm:^1.4.1" - byline: "npm:^5.0.0" - debug: "npm:^4.3.5" - docker-compose: "npm:^0.24.8" - dockerode: "npm:^3.3.5" - get-port: "npm:^5.1.1" - proper-lockfile: "npm:^4.1.2" - properties-reader: "npm:^2.3.0" - ssh-remote-port-forward: "npm:^1.0.4" - tar-fs: "npm:^3.0.6" - tmp: "npm:^0.2.3" - undici: "npm:^5.28.5" - checksum: 10/c15ab1071bcfb4c5713b299184c8431001c05c10a1fd6439e480a50b0721badd641939b1b09a6950d4de2f1ad68450afb824af0feaaf2e96afb41a282e804b88 - languageName: node - linkType: hard - -"text-decoder@npm:^1.1.0": - version: 1.2.3 - resolution: "text-decoder@npm:1.2.3" - dependencies: - b4a: "npm:^1.6.4" - checksum: 10/bcdec33c0f070aeac38e46e4cafdcd567a58473ed308bdf75260bfbd8f7dc76acbc0b13226afaec4a169d0cb44cec2ab89c57b6395ccf02e941eaebbe19e124a - languageName: node - linkType: hard - "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" @@ -7000,22 +4087,6 @@ __metadata: languageName: node linkType: hard -"thread-stream@npm:^2.6.0": - version: 2.7.0 - resolution: "thread-stream@npm:2.7.0" - dependencies: - real-require: "npm:^0.2.0" - checksum: 10/03e743a2ccb2af5fa695d2e4369113336ee9b9f09c4453d50a222cbb4ae3af321bff658e0e5bf8bfbce9d7f5a7bf6262d12a2a365e160f4e76380ec624d32e7b - languageName: node - linkType: hard - -"tmp@npm:^0.2.3": - version: 0.2.3 - resolution: "tmp@npm:0.2.3" - checksum: 10/7b13696787f159c9754793a83aa79a24f1522d47b87462ddb57c18ee93ff26c74cbb2b8d9138f571d2e0e765c728fb2739863a672b280528512c6d83d511c6fa - languageName: node - linkType: hard - "tmpl@npm:1.0.5": version: 1.0.5 resolution: "tmpl@npm:1.0.5" @@ -7032,38 +4103,6 @@ __metadata: languageName: node linkType: hard -"tr46@npm:~0.0.3": - version: 0.0.3 - resolution: "tr46@npm:0.0.3" - checksum: 10/8f1f5aa6cb232f9e1bdc86f485f916b7aa38caee8a778b378ffec0b70d9307873f253f5cbadbe2955ece2ac5c83d0dc14a77513166ccd0a0c7fe197e21396695 - languageName: node - linkType: hard - -"ts-api-utils@npm:^1.0.1": - version: 1.4.3 - resolution: "ts-api-utils@npm:1.4.3" - peerDependencies: - typescript: ">=4.2.0" - checksum: 10/713c51e7392323305bd4867422ba130fbf70873ef6edbf80ea6d7e9c8f41eeeb13e40e8e7fe7cd321d74e4864777329797077268c9f570464303a1723f1eed39 - languageName: node - linkType: hard - -"ts-custom-error@npm:^3.3.1": - version: 3.3.1 - resolution: "ts-custom-error@npm:3.3.1" - checksum: 10/92e3a2c426bf6049579aeb889b6f9787e0cfb6bb715a1457e2571708be7fe739662ca9eb2a8c61b72a2d32189645f4fbcf1a370087e030d922e9e2a7b7c1c994 - languageName: node - linkType: hard - -"ts-invariant@npm:^0.10.3": - version: 0.10.3 - resolution: "ts-invariant@npm:0.10.3" - dependencies: - tslib: "npm:^2.1.0" - checksum: 10/bb07d56fe4aae69d8860e0301dfdee2d375281159054bc24bf1e49e513fb0835bf7f70a11351344d213a79199c5e695f37ebbf5a447188a377ce0cd81d91ddb5 - languageName: node - linkType: hard - "ts-jest@npm:^29.1.1": version: 29.2.6 resolution: "ts-jest@npm:29.2.6" @@ -7139,77 +4178,58 @@ __metadata: languageName: node linkType: hard -"tsconfig-paths@npm:^3.15.0": - version: 3.15.0 - resolution: "tsconfig-paths@npm:3.15.0" - dependencies: - "@types/json5": "npm:^0.0.29" - json5: "npm:^1.0.2" - minimist: "npm:^1.2.6" - strip-bom: "npm:^3.0.0" - checksum: 10/2041beaedc6c271fc3bedd12e0da0cc553e65d030d4ff26044b771fac5752d0460944c0b5e680f670c2868c95c664a256cec960ae528888db6ded83524e33a14 - languageName: node - linkType: hard - -"tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.6.2": - version: 2.8.1 - resolution: "tslib@npm:2.8.1" - checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7 - languageName: node - linkType: hard - -"turbo-darwin-64@npm:1.13.4": - version: 1.13.4 - resolution: "turbo-darwin-64@npm:1.13.4" +"turbo-darwin-64@npm:2.5.1": + version: 2.5.1 + resolution: "turbo-darwin-64@npm:2.5.1" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"turbo-darwin-arm64@npm:1.13.4": - version: 1.13.4 - resolution: "turbo-darwin-arm64@npm:1.13.4" +"turbo-darwin-arm64@npm:2.5.1": + version: 2.5.1 + resolution: "turbo-darwin-arm64@npm:2.5.1" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"turbo-linux-64@npm:1.13.4": - version: 1.13.4 - resolution: "turbo-linux-64@npm:1.13.4" +"turbo-linux-64@npm:2.5.1": + version: 2.5.1 + resolution: "turbo-linux-64@npm:2.5.1" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"turbo-linux-arm64@npm:1.13.4": - version: 1.13.4 - resolution: "turbo-linux-arm64@npm:1.13.4" +"turbo-linux-arm64@npm:2.5.1": + version: 2.5.1 + resolution: "turbo-linux-arm64@npm:2.5.1" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"turbo-windows-64@npm:1.13.4": - version: 1.13.4 - resolution: "turbo-windows-64@npm:1.13.4" +"turbo-windows-64@npm:2.5.1": + version: 2.5.1 + resolution: "turbo-windows-64@npm:2.5.1" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"turbo-windows-arm64@npm:1.13.4": - version: 1.13.4 - resolution: "turbo-windows-arm64@npm:1.13.4" +"turbo-windows-arm64@npm:2.5.1": + version: 2.5.1 + resolution: "turbo-windows-arm64@npm:2.5.1" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"turbo@npm:^1.10.16": - version: 1.13.4 - resolution: "turbo@npm:1.13.4" - dependencies: - turbo-darwin-64: "npm:1.13.4" - turbo-darwin-arm64: "npm:1.13.4" - turbo-linux-64: "npm:1.13.4" - turbo-linux-arm64: "npm:1.13.4" - turbo-windows-64: "npm:1.13.4" - turbo-windows-arm64: "npm:1.13.4" +"turbo@npm:^2.5.1": + version: 2.5.1 + resolution: "turbo@npm:2.5.1" + dependencies: + turbo-darwin-64: "npm:2.5.1" + turbo-darwin-arm64: "npm:2.5.1" + turbo-linux-64: "npm:2.5.1" + turbo-linux-arm64: "npm:2.5.1" + turbo-windows-64: "npm:2.5.1" + turbo-windows-arm64: "npm:2.5.1" dependenciesMeta: turbo-darwin-64: optional: true @@ -7225,14 +4245,7 @@ __metadata: optional: true bin: turbo: bin/turbo - checksum: 10/b8187def43760428e117313fc4a559af5c02b473d816b3efef406165c2c45cf3a256fbda4b15f0c1a48ccd188bd43cf93686f2aeab176a15a01553cd165071cc - languageName: node - linkType: hard - -"tweetnacl@npm:^0.14.3": - version: 0.14.5 - resolution: "tweetnacl@npm:0.14.5" - checksum: 10/04ee27901cde46c1c0a64b9584e04c96c5fe45b38c0d74930710751ea991408b405747d01dfae72f80fc158137018aea94f9c38c651cb9c318f0861a310c3679 + checksum: 10/54d7c16d7cc9b60098db62d37940bef4663a14344bada1cb521e3260b6c30ec4bebc88a3dbb4108e4a3436fdc32b43091323f9d841ad3198719513765a73ddd9 languageName: node linkType: hard @@ -7266,59 +4279,6 @@ __metadata: languageName: node linkType: hard -"typed-array-buffer@npm:^1.0.3": - version: 1.0.3 - resolution: "typed-array-buffer@npm:1.0.3" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-typed-array: "npm:^1.1.14" - checksum: 10/3fb91f0735fb413b2bbaaca9fabe7b8fc14a3fa5a5a7546bab8a57e755be0e3788d893195ad9c2b842620592de0e68d4c077d4c2c41f04ec25b8b5bb82fa9a80 - languageName: node - linkType: hard - -"typed-array-byte-length@npm:^1.0.3": - version: 1.0.3 - resolution: "typed-array-byte-length@npm:1.0.3" - dependencies: - call-bind: "npm:^1.0.8" - for-each: "npm:^0.3.3" - gopd: "npm:^1.2.0" - has-proto: "npm:^1.2.0" - is-typed-array: "npm:^1.1.14" - checksum: 10/269dad101dda73e3110117a9b84db86f0b5c07dad3a9418116fd38d580cab7fc628a4fc167e29b6d7c39da2f53374b78e7cb578b3c5ec7a556689d985d193519 - languageName: node - linkType: hard - -"typed-array-byte-offset@npm:^1.0.4": - version: 1.0.4 - resolution: "typed-array-byte-offset@npm:1.0.4" - dependencies: - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - for-each: "npm:^0.3.3" - gopd: "npm:^1.2.0" - has-proto: "npm:^1.2.0" - is-typed-array: "npm:^1.1.15" - reflect.getprototypeof: "npm:^1.0.9" - checksum: 10/c2869aa584cdae24ecfd282f20a0f556b13a49a9d5bca1713370bb3c89dff0ccbc5ceb45cb5b784c98f4579e5e3e2a07e438c3a5b8294583e2bd4abbd5104fb5 - languageName: node - linkType: hard - -"typed-array-length@npm:^1.0.7": - version: 1.0.7 - resolution: "typed-array-length@npm:1.0.7" - dependencies: - call-bind: "npm:^1.0.7" - for-each: "npm:^0.3.3" - gopd: "npm:^1.0.1" - is-typed-array: "npm:^1.1.13" - possible-typed-array-names: "npm:^1.0.0" - reflect.getprototypeof: "npm:^1.0.6" - checksum: 10/d6b2f0e81161682d2726eb92b1dc2b0890890f9930f33f9bcf6fc7272895ce66bc368066d273e6677776de167608adc53fcf81f1be39a146d64b630edbf2081c - languageName: node - linkType: hard - "typescript@npm:^5.2.2": version: 5.8.2 resolution: "typescript@npm:5.8.2" @@ -7339,18 +4299,6 @@ __metadata: languageName: node linkType: hard -"unbox-primitive@npm:^1.1.0": - version: 1.1.0 - resolution: "unbox-primitive@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.3" - has-bigints: "npm:^1.0.2" - has-symbols: "npm:^1.1.0" - which-boxed-primitive: "npm:^1.1.1" - checksum: 10/fadb347020f66b2c8aeacf8b9a79826fa34cc5e5457af4eb0bbc4e79bd87fed0fa795949825df534320f7c13f199259516ad30abc55a6e7b91d8d996ca069e50 - languageName: node - linkType: hard - "undici-types@npm:~5.26.4": version: 5.26.5 resolution: "undici-types@npm:5.26.5" @@ -7365,15 +4313,6 @@ __metadata: languageName: node linkType: hard -"undici@npm:^5.28.5": - version: 5.28.5 - resolution: "undici@npm:5.28.5" - dependencies: - "@fastify/busboy": "npm:^2.0.0" - checksum: 10/459cd84ab75fe90d696fa2634a8b5b23f9e1080b27236c6809bd74e51862be85df6d95b4a8fed3ee42554495008cb3c05f1bc9d4a1807478f433cca567003d70 - languageName: node - linkType: hard - "unique-filename@npm:^4.0.0": version: 4.0.0 resolution: "unique-filename@npm:4.0.0" @@ -7392,13 +4331,6 @@ __metadata: languageName: node linkType: hard -"universalify@npm:^2.0.0": - version: 2.0.1 - resolution: "universalify@npm:2.0.1" - checksum: 10/ecd8469fe0db28e7de9e5289d32bd1b6ba8f7183db34f3bfc4ca53c49891c2d6aa05f3fb3936a81285a905cc509fb641a0c3fc131ec786167eff41236ae32e60 - languageName: node - linkType: hard - "update-browserslist-db@npm:^1.1.1": version: 1.1.3 resolution: "update-browserslist-db@npm:1.1.3" @@ -7422,22 +4354,6 @@ __metadata: languageName: node linkType: hard -"util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 10/474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 - languageName: node - linkType: hard - -"uuid@npm:^8.3.2": - version: 8.3.2 - resolution: "uuid@npm:8.3.2" - bin: - uuid: dist/bin/uuid - checksum: 10/9a5f7aa1d6f56dd1e8d5f2478f855f25c645e64e26e347a98e98d95781d5ed20062d6cca2eecb58ba7c84bc3910be95c0451ef4161906abaab44f9cb68ffbdd1 - languageName: node - linkType: hard - "v8-compile-cache-lib@npm:^3.0.1": version: 3.0.1 resolution: "v8-compile-cache-lib@npm:3.0.1" @@ -7465,90 +4381,6 @@ __metadata: languageName: node linkType: hard -"web-streams-polyfill@npm:^3.0.3": - version: 3.3.3 - resolution: "web-streams-polyfill@npm:3.3.3" - checksum: 10/8e7e13501b3834094a50abe7c0b6456155a55d7571312b89570012ef47ec2a46d766934768c50aabad10a9c30dd764a407623e8bfcc74fcb58495c29130edea9 - languageName: node - linkType: hard - -"webidl-conversions@npm:^3.0.0": - version: 3.0.1 - resolution: "webidl-conversions@npm:3.0.1" - checksum: 10/b65b9f8d6854572a84a5c69615152b63371395f0c5dcd6729c45789052296df54314db2bc3e977df41705eacb8bc79c247cee139a63fa695192f95816ed528ad - languageName: node - linkType: hard - -"whatwg-url@npm:^5.0.0": - version: 5.0.0 - resolution: "whatwg-url@npm:5.0.0" - dependencies: - tr46: "npm:~0.0.3" - webidl-conversions: "npm:^3.0.0" - checksum: 10/f95adbc1e80820828b45cc671d97da7cd5e4ef9deb426c31bcd5ab00dc7103042291613b3ef3caec0a2335ed09e0d5ed026c940755dbb6d404e2b27f940fdf07 - languageName: node - linkType: hard - -"which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": - version: 1.1.1 - resolution: "which-boxed-primitive@npm:1.1.1" - dependencies: - is-bigint: "npm:^1.1.0" - is-boolean-object: "npm:^1.2.1" - is-number-object: "npm:^1.1.1" - is-string: "npm:^1.1.1" - is-symbol: "npm:^1.1.1" - checksum: 10/a877c0667bc089518c83ad4d845cf8296b03efe3565c1de1940c646e00a2a1ae9ed8a185bcfa27cbf352de7906f0616d83b9d2f19ca500ee02a551fb5cf40740 - languageName: node - linkType: hard - -"which-builtin-type@npm:^1.2.1": - version: 1.2.1 - resolution: "which-builtin-type@npm:1.2.1" - dependencies: - call-bound: "npm:^1.0.2" - function.prototype.name: "npm:^1.1.6" - has-tostringtag: "npm:^1.0.2" - is-async-function: "npm:^2.0.0" - is-date-object: "npm:^1.1.0" - is-finalizationregistry: "npm:^1.1.0" - is-generator-function: "npm:^1.0.10" - is-regex: "npm:^1.2.1" - is-weakref: "npm:^1.0.2" - isarray: "npm:^2.0.5" - which-boxed-primitive: "npm:^1.1.0" - which-collection: "npm:^1.0.2" - which-typed-array: "npm:^1.1.16" - checksum: 10/22c81c5cb7a896c5171742cd30c90d992ff13fb1ea7693e6cf80af077791613fb3f89aa9b4b7f890bd47b6ce09c6322c409932359580a2a2a54057f7b52d1cbe - languageName: node - linkType: hard - -"which-collection@npm:^1.0.2": - version: 1.0.2 - resolution: "which-collection@npm:1.0.2" - dependencies: - is-map: "npm:^2.0.3" - is-set: "npm:^2.0.3" - is-weakmap: "npm:^2.0.2" - is-weakset: "npm:^2.0.3" - checksum: 10/674bf659b9bcfe4055f08634b48a8588e879161b9fefed57e9ec4ff5601e4d50a05ccd76cf10f698ef5873784e5df3223336d56c7ce88e13bcf52ebe582fc8d7 - languageName: node - linkType: hard - -"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.18": - version: 1.1.18 - resolution: "which-typed-array@npm:1.1.18" - dependencies: - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - for-each: "npm:^0.3.3" - gopd: "npm:^1.2.0" - has-tostringtag: "npm:^1.0.2" - checksum: 10/11eed801b2bd08cdbaecb17aff381e0fb03526532f61acc06e6c7b9370e08062c33763a51f27825f13fdf34aabd0df6104007f4e8f96e6eaef7db0ce17a26d6e - languageName: node - linkType: hard - "which@npm:^2.0.1": version: 2.0.2 resolution: "which@npm:2.0.2" @@ -7617,28 +4449,6 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.14.2, ws@npm:^8.8.1": - version: 8.18.1 - resolution: "ws@npm:8.18.1" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 10/3f38e9594f2af5b6324138e86b74df7d77bbb8e310bf8188679dd80bac0d1f47e51536a1923ac3365f31f3d8b25ea0b03e4ade466aa8292a86cd5defca64b19b - languageName: node - linkType: hard - -"xml@npm:^1.0.1": - version: 1.0.1 - resolution: "xml@npm:1.0.1" - checksum: 10/6c4c31a1308e45732e5ac6b50edbca0e8f7abe5cb5de10215d8e3c688819fe7c7706e056f6fb59b1a23fdf1000c2d7a8bba0a89e94aa1796cd2376d9a5ba401e - languageName: node - linkType: hard - "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8" @@ -7667,15 +4477,6 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^2.2.2": - version: 2.7.0 - resolution: "yaml@npm:2.7.0" - bin: - yaml: bin.mjs - checksum: 10/c8c314c62fbd49244a6a51b06482f6d495b37ab10fa685fcafa1bbaae7841b7233ee7d12cab087bcca5a0b28adc92868b6e437322276430c28d00f1c1732eeec - languageName: node - linkType: hard - "yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" @@ -7711,30 +4512,3 @@ __metadata: checksum: 10/f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 languageName: node linkType: hard - -"zen-observable-ts@npm:^1.1.0, zen-observable-ts@npm:^1.2.5": - version: 1.2.5 - resolution: "zen-observable-ts@npm:1.2.5" - dependencies: - zen-observable: "npm:0.8.15" - checksum: 10/2384cf92a60e39e7b9735a0696f119684fee0f8bcc81d71474c92d656eca1bc3e87b484a04e97546e56bd539f8756bf97cf21a28a933ff7a94b35a8d217848eb - languageName: node - linkType: hard - -"zen-observable@npm:0.8.15": - version: 0.8.15 - resolution: "zen-observable@npm:0.8.15" - checksum: 10/30eac3f4055d33f446b4cd075d3543da347c2c8e68fbc35c3f5a19fb43be67c6ed27ee136bc8f8933efa547be7ce04957809ad00ee7f1b00a964f199ae6fb514 - languageName: node - linkType: hard - -"zip-stream@npm:^6.0.1": - version: 6.0.1 - resolution: "zip-stream@npm:6.0.1" - dependencies: - archiver-utils: "npm:^5.0.0" - compress-commons: "npm:^6.0.2" - readable-stream: "npm:^4.0.0" - checksum: 10/aa5abd6a89590eadeba040afbc375f53337f12637e5e98330012a12d9886cde7a3ccc28bd91aafab50576035bbb1de39a9a316eecf2411c8b9009c9f94f0db27 - languageName: node - linkType: hard From 7e12f040bad2a90b2314805a93f0214b112f419e Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 6 May 2025 20:27:14 -0400 Subject: [PATCH 073/282] Add PR and issue templates (#43) * Add issue templates * add PR template * add checklist --- .github/ISSUE_TEMPLATE/bug_report.md | 20 ++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 14 ++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 18 ++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..2a32821c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,20 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + + + + + +**📝 Details** + + + +**🔢 Code to reproduce bug** + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..2e09ebfb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,14 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**🧐 Motivation** + + +**📝 Details** + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..b1e26cc5 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ + + + + + +Fixes #??? + + + + +#### PR Checklist + + + + + +- [ ] Tests +- [ ] Documentation From d0261038da4aa33966304ade17dcba6edcafa49f Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 6 May 2025 20:32:14 -0400 Subject: [PATCH 074/282] Add security doc (#42) * add security section and doc * fix email * Update README.md Co-authored-by: Iskander <0xisk@proton.me> * fix bare url --------- Co-authored-by: Iskander <0xisk@proton.me> --- README.md | 6 ++++++ SECURITY.md | 3 +++ 2 files changed, 9 insertions(+) create mode 100644 SECURITY.md diff --git a/README.md b/README.md index 90f64ec7..6e1966e2 100644 --- a/README.md +++ b/README.md @@ -29,3 +29,9 @@ npx turbo build ```bash npx turbo test ``` + +## Security + +This project is still in a very early and experimental phase. It has never been audited nor thoroughly reviewed for security vulnerabilities. DO NOT USE IT IN PRODUCTION. + +Please report any security issues you find to . diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..8b23055a --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,3 @@ +# Security + +Security vulnerabilities should be disclosed to the project maintainers by email to . From 25cadf0930a393a62daf90a496a97b5890d25f39 Mon Sep 17 00:00:00 2001 From: Iskander Date: Fri, 9 May 2025 04:23:45 +0200 Subject: [PATCH 075/282] chore: add code owners (#53) --- .github/CODEOWNERS | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..7ef4cc84 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,16 @@ +# Lines starting with '#' are comments. +# Each line is a file pattern followed by one or more owners. + +# More details are here: https://help.github.com/articles/about-codeowners/ + +# The '*' pattern is global owners. + +# Order is important. The last matching pattern has the most precedence. +# The folders are ordered as follows: + +# In each subsection folders are ordered first by depth, then alphabetically. +# This should make it easy to add new rules without breaking existing ones. + +# Global: + +* @andrew-fleming @emnul @0xisk From e4c01a65d8fc543e1ac448055323e36f53292736 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Wed, 14 May 2025 14:34:00 -0400 Subject: [PATCH 076/282] Improve compact scripts (#41) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bump midnight-js * remove unused deps * remove eslint and prettier, add biome * run fmt * run lint * organize imports * remove dev deps from contracts/ * remove unused deps * update turbo and scripts * add clean script * add clean script * clean up test config * remove jest reporters * bump turbo to 2.5 * bump turbo * fix package names * set up compact compiler and builder * update scripts * update yarn.lock * update readme * fix fmt * fix fmt * remove lingering file * update biome, fix fmt * add requirements in dev section * add devdeps to contracts packages * simplify workspace * remove unnecessary button rule * fix fmt * remove useExhaustiveDeps rule * Uses recommended compiler options for Node 22 and TypeScript 5.8 * Update compact/src/Builder.ts Co-authored-by: Iskander <0xisk@proton.me> * remove author * Apply suggestions from code review Co-authored-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> * Update biome.json Co-authored-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> * fix correctness and a11y * remove implicit trailingCommas and indentWidth * add stderr discard notice * change dirent.path to parentPath * add getCompactFiles method * fix lint * Improves type safety via custom error type * output will never be null * remove redundant check * Colocate error types into their own file * Adds type guard to `executeStep` * Add type guard to `compileFile` * Fix fmt * update printOutput function signature --------- Co-authored-by: Emanuel Solis Co-authored-by: Iskander <0xisk@proton.me> Co-authored-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- README.md | 14 +- biome.json | 56 +- compact/package.json | 41 +- compact/src/Builder.ts | 159 ++++ compact/src/Compiler.ts | 199 ++++ compact/src/run-compactc.cjs | 32 - compact/src/runBuilder.ts | 43 + compact/src/runCompiler.ts | 40 + compact/src/types/errors.ts | 28 + compact/tsconfig.json | 25 + contracts/erc721/src/test/utils/index.ts | 2 - contracts/utils/package.json | 10 +- contracts/utils/src/test/utils/index.ts | 10 - package.json | 6 +- yarn.lock | 1065 +++++++--------------- 15 files changed, 936 insertions(+), 794 deletions(-) create mode 100755 compact/src/Builder.ts create mode 100755 compact/src/Compiler.ts delete mode 100755 compact/src/run-compactc.cjs create mode 100644 compact/src/runBuilder.ts create mode 100644 compact/src/runCompiler.ts create mode 100644 compact/src/types/errors.ts create mode 100644 compact/tsconfig.json delete mode 100644 contracts/erc721/src/test/utils/index.ts delete mode 100644 contracts/utils/src/test/utils/index.ts diff --git a/README.md b/README.md index 6e1966e2..149a52b2 100644 --- a/README.md +++ b/README.md @@ -10,18 +10,24 @@ ## Development +> ### Requirements +> +> - [node](https://nodejs.org/) +> - [yarn](https://yarnpkg.com/getting-started/install) +> - [compact](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) + Clone the repository: ```bash git clone git@github.com:OpenZeppelin/midnight-contracts.git ``` -`cd` into it and then install dependencies and build: +`cd` into it and then install dependencies, prepare compiler, and compile: ```bash -cd midnight-contracts -yarn -npx turbo build +yarn && \ +yarn run prepare && \ +npx turbo compact ``` ### Run tests diff --git a/biome.json b/biome.json index 656beeee..8bf55b0a 100644 --- a/biome.json +++ b/biome.json @@ -24,15 +24,65 @@ "organizeImports": { "enabled": true }, - "linter": { +"linter": { "enabled": true, "rules": { - "recommended": true + "recommended": true, + "a11y": { + "all": false + }, + "correctness": { + "noUnusedVariables": "error", + "noUnusedImports": "error", + "noChildrenProp": "off", + "noInvalidDirectionInLinearGradient": "off", + "noInvalidGridAreas": "off", + "noInvalidPositionAtImportRule": "off", + "noRenderReturnValue": "off", + "noUnknownFunction": "off", + "noUnknownMediaFeatureName": "off", + "noUnknownProperty": "off", + "noUnknownUnit": "off", + "noUnmatchableAnbSelector": "off", + "useExhaustiveDependencies": "off", + "useJsxKeyInIterable": "off" + }, + "performance": { + "noBarrelFile": "error", + "noReExportAll": "error", + "noDelete": "off" + }, + "style": { + "noNonNullAssertion": "off", + "useShorthandArrayType": "error" + }, + "suspicious": { + "noArrayIndexKey": "off", + "noConfusingVoidType": "off", + "noConsoleLog": "error", + "noExplicitAny": "off", + "noCommentText": "off", + "noDuplicateAtImportRules": "off", + "noDuplicateFontNames": "off", + "noDuplicateJsxProps": "off", + "noDuplicateSelectorsKeyframeBlock": "off", + "noEmptyBlock": "off", + "noImportantInKeyframe": "off", + "noShorthandPropertyOverrides": "off", + "noSuspiciousSemicolonInJsx": "off", + "useErrorMessage": "error" + }, + "security": { + "noDangerouslySetInnerHtml": "off", + "noDangerouslySetInnerHtmlWithChildren": "off" + } } }, "javascript": { "formatter": { - "quoteStyle": "single" + "quoteStyle": "single", + "semicolons": "always", + "indentStyle": "space" } } } diff --git a/compact/package.json b/compact/package.json index a2ab6849..7e811f4f 100644 --- a/compact/package.json +++ b/compact/package.json @@ -1,17 +1,40 @@ { - "name": "@midnight-ntwrk/compact", + "packageManager": "yarn@4.1.0", + "name": "@openzeppelin-midnight/compact", + "version": "0.0.1", + "keywords": ["compact", "compiler"], + "author": "", + "license": "MIT", "description": "Compact fetcher", - "author": "IOG", - "license": "Apache-2.0", - "private": true, - "version": "0.21.0", "type": "module", + "exports": "./index.js", + "engines": { + "node": ">=18" + }, "bin": { - "run-compactc": "src/run-compactc.cjs" + "compact-builder": "dist/runBuilder.js", + "compact-compiler": "dist/runCompiler.js" + }, + "scripts": { + "types": "tsc -p tsconfig.json --noEmit", + "fmt": "biome format", + "fmt:fix": "biome format --write", + "lint": "biome lint", + "lint:fix": "biome check --write", + "clean": "git clean -fXd" }, "devDependencies": { - "eslint": "^8.52.0", - "ts-node": "^10.9.2", - "typescript": "^5.2.2" + "@types/jest": "^29.5.6", + "@types/node": "^22.13.10", + "fast-check": "^3.15.0", + "jest": "^29.7.0", + "jest-fast-check": "^2.0.0", + "ts-jest": "^29.1.1", + "typescript": "^5.8.2" + }, + "dependencies": { + "chalk": "^5.4.1", + "log-symbols": "^7.0.0", + "ora": "^8.2.0" } } diff --git a/compact/src/Builder.ts b/compact/src/Builder.ts new file mode 100755 index 00000000..48130070 --- /dev/null +++ b/compact/src/Builder.ts @@ -0,0 +1,159 @@ +#!/usr/bin/env node + +import { exec } from 'node:child_process'; +import { promisify } from 'node:util'; +import chalk from 'chalk'; +import ora, { type Ora } from 'ora'; +import { CompactCompiler } from './Compiler.js'; +import { isPromisifiedChildProcessError } from './types/errors.js'; + +// Promisified exec for async execution +const execAsync = promisify(exec); + +/** + * A class to handle the build process for a project. + * Runs CompactCompiler as a prerequisite, then executes build steps (TypeScript compilation, + * artifact copying, etc.) + * with progress feedback and colored output for success and error states. + * + * @notice `cmd` scripts discard `stderr` output and fail silently because this is + * handled in `executeStep`. + * + * @example + * ```typescript + * const builder = new ProjectBuilder('--skip-zk'); // Optional flags for compactc + * builder.build().catch(err => console.error(err)); + * ``` + * + * @example Successful Build Output + * ``` + * ℹ [COMPILE] Found 2 .compact file(s) to compile + * ✔ [COMPILE] [1/2] Compiled AccessControl.compact + * Compactc version: 0.22.0 + * ✔ [COMPILE] [2/2] Compiled MockAccessControl.compact + * Compactc version: 0.22.0 + * ✔ [BUILD] [1/3] Compiling TypeScript + * ✔ [BUILD] [2/3] Copying artifacts + * ✔ [BUILD] [3/3] Copying and cleaning .compact files + * ``` + * + * @example Failed Compilation Output + * ``` + * ℹ [COMPILE] Found 2 .compact file(s) to compile + * ✖ [COMPILE] [1/2] Failed AccessControl.compact + * Compactc version: 0.22.0 + * Error: Expected ';' at line 5 in AccessControl.compact + * ``` + * + * @example Failed Build Step Output + * ``` + * ℹ [COMPILE] Found 2 .compact file(s) to compile + * ✔ [COMPILE] [1/2] Compiled AccessControl.compact + * ✔ [COMPILE] [2/2] Compiled MockAccessControl.compact + * ✖ [BUILD] [1/3] Failed Compiling TypeScript + * error TS1005: ';' expected at line 10 in file.ts + * [BUILD] ❌ Build failed: Command failed: tsc --project tsconfig.build.json + * ``` + */ +export class CompactBuilder { + private readonly compilerFlags: string; + private readonly steps: Array<{ cmd: string; msg: string; shell?: string }> = + [ + { + cmd: 'tsc --project tsconfig.build.json', + msg: 'Compiling TypeScript', + }, + { + cmd: 'mkdir -p dist/artifacts && cp -Rf src/artifacts/* dist/artifacts/ 2>/dev/null || true', + msg: 'Copying artifacts', + shell: '/bin/bash', + }, + { + cmd: 'mkdir -p dist && find src -type f -name "*.compact" -exec cp {} dist/ \\; 2>/dev/null && rm dist/Mock*.compact 2>/dev/null || true', + msg: 'Copying and cleaning .compact files', + shell: '/bin/bash', + }, + ]; + + /** + * Constructs a new ProjectBuilder instance. + * @param compilerFlags - Optional space-separated string of `compactc` flags (e.g., "--skip-zk") + */ + constructor(compilerFlags = '') { + this.compilerFlags = compilerFlags; + } + + /** + * Executes the full build process: compiles .compact files first, then runs build steps. + * Displays progress with spinners and outputs results in color. + * + * @returns A promise that resolves when all steps complete successfully + * @throws Error if compilation or any build step fails + */ + public async build(): Promise { + // Run compact compilation as a prerequisite + const compiler = new CompactCompiler(this.compilerFlags); + await compiler.compile(); + + // Proceed with build steps + for (const [index, step] of this.steps.entries()) { + await this.executeStep(step, index, this.steps.length); + } + } + + /** + * Executes a single build step. + * Runs the command, shows a spinner, and prints output with indentation. + * + * @param step - The build step containing command and message + * @param index - Current step index (0-based) for progress display + * @param total - Total number of steps for progress display + * @returns A promise that resolves when the step completes successfully + * @throws Error if the step fails + */ + private async executeStep( + step: { cmd: string; msg: string; shell?: string }, + index: number, + total: number, + ): Promise { + const stepLabel: string = `[${index + 1}/${total}]`; + const spinner: Ora = ora(`[BUILD] ${stepLabel} ${step.msg}`).start(); + + try { + const { stdout, stderr }: { stdout: string; stderr: string } = + await execAsync(step.cmd, { + shell: step.shell, // Only pass shell where needed + }); + spinner.succeed(`[BUILD] ${stepLabel} ${step.msg}`); + this.printOutput(stdout, chalk.cyan); + this.printOutput(stderr, chalk.yellow); // Show stderr (warnings) in yellow if present + } catch (error: unknown) { + spinner.fail(`[BUILD] ${stepLabel} ${step.msg}`); + if (isPromisifiedChildProcessError(error)) { + this.printOutput(error.stdout, chalk.cyan); + this.printOutput(error.stderr, chalk.red); + console.error(chalk.red('[BUILD] ❌ Build failed:', error.message)); + } else if (error instanceof Error) { + console.error(chalk.red('[BUILD] ❌ Build failed:', error.message)); + } + + process.exit(1); + } + } + + /** + * Prints command output with indentation and specified color. + * Filters out empty lines and indents each line for readability. + * + * @param output - The command output string to print (stdout or stderr) + * @param colorFn - Chalk color function to style the output (e.g., `chalk.cyan` for success, `chalk.red` for errors) + */ + private printOutput(output: string, colorFn: (text: string) => string): void { + const lines: string[] = output + .split('\n') + .filter((line: string): boolean => line.trim() !== '') + .map((line: string): string => ` ${line}`); + // biome-ignore lint/suspicious/noConsoleLog: needed for debugging + console.log(colorFn(lines.join('\n'))); + } +} diff --git a/compact/src/Compiler.ts b/compact/src/Compiler.ts new file mode 100755 index 00000000..f58da606 --- /dev/null +++ b/compact/src/Compiler.ts @@ -0,0 +1,199 @@ +#!/usr/bin/env node + +import { exec as execCallback } from 'node:child_process'; +import { existsSync } from 'node:fs'; +import { readdir } from 'node:fs/promises'; +import { basename, dirname, join, relative, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { promisify } from 'node:util'; +import chalk from 'chalk'; +import ora, { type Ora } from 'ora'; +import { isPromisifiedChildProcessError } from './types/errors.ts'; + +const DIRNAME: string = dirname(fileURLToPath(import.meta.url)); +const SRC_DIR: string = 'src'; +const ARTIFACTS_DIR: string = 'src/artifacts'; +const COMPACT_HOME: string = + process.env.COMPACT_HOME ?? resolve(DIRNAME, '../compactc'); +const COMPACTC_PATH: string = join(COMPACT_HOME, 'compactc'); + +/** + * A class to handle compilation of `.compact` files using the `compactc` compiler. + * Provides progress feedback and colored output for success and error states. + * + * @example + * ```typescript + * const compiler = new CompactCompiler('--skip-zk'); + * compiler.compile().catch(err => console.error(err)); + * ``` + * + * @example Successful Compilation Output + * ``` + * ℹ [COMPILE] Found 2 .compact file(s) to compile + * ✔ [COMPILE] [1/2] Compiled AccessControl.compact + * Compactc version: 0.22.0 + * ✔ [COMPILE] [2/2] Compiled MockAccessControl.compact + * Compactc version: 0.22.0 + * Compiling circuit "src/artifacts/MockAccessControl/zkir/grantRole.zkir"... (skipped proving keys) + * ``` + * + * @example Failed Compilation Output + * ``` + * ℹ [COMPILE] Found 2 .compact file(s) to compile + * ✖ [COMPILE] [1/2] Failed AccessControl.compact + * Compactc version: 0.22.0 + * Error: Expected ';' at line 5 in AccessControl.compact + * ``` + */ +export class CompactCompiler { + /** Stores the compiler flags passed via command-line arguments */ + private readonly flags: string; + + /** + * Constructs a new CompactCompiler instance, validating the `compactc` binary path. + * + * @param flags - Space-separated string of `compactc` flags (e.g., "--skip-zk --no-communications-commitment") + * @throws {Error} If the `compactc` binary is not found at the resolved path + */ + constructor(flags: string) { + this.flags = flags.trim(); + const spinner = ora(); + + spinner.info(chalk.blue(`[COMPILE] COMPACT_HOME: ${COMPACT_HOME}`)); + spinner.info(chalk.blue(`[COMPILE] COMPACTC_PATH: ${COMPACTC_PATH}`)); + + if (!existsSync(COMPACTC_PATH)) { + spinner.fail( + chalk.red( + `[COMPILE] Error: compactc not found at ${COMPACTC_PATH}. Set COMPACT_HOME to the compactc binary path.`, + ), + ); + throw new Error(`compactc not found at ${COMPACTC_PATH}`); + } + } + + /** + * Compiles all `.compact` files in the source directory and its subdirectories (e.g., `src/test/mock/`). + * Scans the `src` directory recursively for `.compact` files, compiles each one using `compactc`, + * and displays progress with a spinner and colored output. + * + * @returns A promise that resolves when all files are compiled successfully + * @throws {Error} If compilation fails for any file + */ + public async compile(): Promise { + const compactFiles: string[] = await this.getCompactFiles(SRC_DIR); + + const spinner = ora(); + if (compactFiles.length === 0) { + spinner.warn(chalk.yellow('[COMPILE] No .compact files found.')); + return; + } + + spinner.info( + chalk.blue( + `[COMPILE] Found ${compactFiles.length} .compact file(s) to compile`, + ), + ); + + for (const [index, file] of compactFiles.entries()) { + await this.compileFile(file, index, compactFiles.length); + } + } + + /** + * Recursively scans directory and returns an array of relative paths to `.compact` + * files found within it. + * + * @param dir - The absolute or relative path to the directory to scan. + * @returns A promise that resolves to an array of relative paths from `SRC_DIR` + * to each `.compact` file. + * + * @throws Will log an error if a dir cannot be read or if a file or subdir + * fails to be accessed. It will not reject the promise. Errors are handled + * internally and skipped. + */ + private async getCompactFiles(dir: string): Promise { + try { + const dirents = await readdir(dir, { withFileTypes: true }); + const filePromises = dirents.map(async (entry) => { + const fullPath = join(dir, entry.name); + try { + if (entry.isDirectory()) { + return await this.getCompactFiles(fullPath); + } + + if (entry.isFile() && fullPath.endsWith('.compact')) { + return [relative(SRC_DIR, fullPath)]; + } + return []; + } catch (err) { + console.warn(`Error accessing ${fullPath}:`, err); + return []; + } + }); + + const results = await Promise.all(filePromises); + return results.flat(); + } catch (err) { + console.error(`Failed to read dir: ${dir}`, err); + return []; + } + } + + /** + * Compiles a single `.compact` file. + * Executes the `compactc` compiler with the provided flags, input file, and output directory. + * + * @param file - Relative path of the `.compact` file to compile (e.g., "test/mock/MockFile.compact") + * @param index - Current file index (0-based) for progress display + * @param total - Total number of files to compile for progress display + * @returns A promise that resolves when the file is compiled successfully + * @throws {Error} If compilation fails + */ + private async compileFile( + file: string, + index: number, + total: number, + ): Promise { + const execAsync = promisify(execCallback); + const inputPath: string = join(SRC_DIR, file); + const outputDir: string = join(ARTIFACTS_DIR, basename(file, '.compact')); + const step: string = `[${index + 1}/${total}]`; + const spinner: Ora = ora( + chalk.blue(`[COMPILE] ${step} Compiling ${file}`), + ).start(); + + try { + const command: string = + `${COMPACTC_PATH} ${this.flags} "${inputPath}" "${outputDir}"`.trim(); + spinner.text = chalk.blue(`[COMPILE] ${step} Running: ${command}`); + const { stdout, stderr }: { stdout: string; stderr: string } = + await execAsync(command); + spinner.succeed(chalk.green(`[COMPILE] ${step} Compiled ${file}`)); + this.printOutput(stdout, chalk.cyan); + this.printOutput(stderr, chalk.yellow); + } catch (error: unknown) { + spinner.fail(chalk.red(`[COMPILE] ${step} Failed ${file}`)); + if (isPromisifiedChildProcessError(error)) { + this.printOutput(error.stdout, chalk.cyan); + this.printOutput(error.stderr, chalk.red); + } + throw error; + } + } + + /** + * Prints compiler output with indentation and specified color. + * + * @param output - The compiler output string to print (stdout or stderr) + * @param colorFn - Chalk color function to style the output (e.g., `chalk.cyan` for success, `chalk.red` for errors) + */ + private printOutput(output: string, colorFn: (text: string) => string): void { + const lines: string[] = output + .split('\n') + .filter((line: string): boolean => line.trim() !== '') + .map((line: string): string => ` ${line}`); + // biome-ignore lint/suspicious/noConsoleLog: needed for debugging + console.log(colorFn(lines.join('\n'))); + } +} diff --git a/compact/src/run-compactc.cjs b/compact/src/run-compactc.cjs deleted file mode 100755 index dca2891f..00000000 --- a/compact/src/run-compactc.cjs +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env node - -const childProcess = require('node:child_process'); -const path = require('node:path'); - -const [_node, _script, ...args] = process.argv; -const COMPACT_HOME_ENV = process.env.COMPACT_HOME; - -let compactPath; -if (COMPACT_HOME_ENV != null) { - compactPath = COMPACT_HOME_ENV; - console.log( - `COMPACT_HOME env variable is set; using Compact from ${compactPath}`, - ); -} else { - compactPath = path.resolve(__dirname, '..', 'compactc'); - console.log( - `COMPACT_HOME env variable is not set; using fetched compact from ${compactPath}`, - ); -} - -// yarn runs everything with node... -const child = childProcess.spawn(path.resolve(compactPath, 'compactc'), args, { - stdio: 'inherit', -}); -child.on('exit', (code, signal) => { - if (code === 0) { - process.exit(0); - } else { - process.exit(code ?? signal); - } -}); diff --git a/compact/src/runBuilder.ts b/compact/src/runBuilder.ts new file mode 100644 index 00000000..bf55d90d --- /dev/null +++ b/compact/src/runBuilder.ts @@ -0,0 +1,43 @@ +#!/usr/bin/env node + +import chalk from 'chalk'; +import ora from 'ora'; +import { CompactBuilder } from './Builder.js'; + +/** + * Executes the Compact builder CLI. + * Builds projects using the `CompactBuilder` class with provided flags, including compilation and additional steps. + * + * @example + * ```bash + * npx compact-builder --skip-zk + * ``` + * Expected output: + * ``` + * ℹ [BUILD] Compact builder started + * ℹ [COMPILE] COMPACT_HOME: /path/to/compactc + * ℹ [COMPILE] COMPACTC_PATH: /path/to/compactc/compactc + * ℹ [COMPILE] Found 1 .compact file(s) to compile + * ✔ [COMPILE] [1/1] Compiled Foo.compact + * Compactc version: 0.22.0 + * ✔ [BUILD] [1/3] Compiling TypeScript + * ✔ [BUILD] [2/3] Copying artifacts + * ✔ [BUILD] [3/3] Copying and cleaning .compact files + * ``` + */ +async function runBuilder(): Promise { + const spinner = ora(chalk.blue('[BUILD] Compact Builder started')).info(); + + try { + const compilerFlags = process.argv.slice(2).join(' '); + const builder = new CompactBuilder(compilerFlags); + await builder.build(); + } catch (err) { + spinner.fail( + chalk.red('[BUILD] Unexpected error:', (err as Error).message), + ); + process.exit(1); + } +} + +runBuilder(); diff --git a/compact/src/runCompiler.ts b/compact/src/runCompiler.ts new file mode 100644 index 00000000..27de79d0 --- /dev/null +++ b/compact/src/runCompiler.ts @@ -0,0 +1,40 @@ +#!/usr/bin/env node + +import chalk from 'chalk'; +import ora from 'ora'; +import { CompactCompiler } from './Compiler.js'; + +/** + * Executes the Compact compiler CLI. + * Compiles `.compact` files using the `CompactCompiler` class with provided flags. + * + * @example + * ```bash + * npx compact-compiler --skip-zk + * ``` + * Expected output: + * ``` + * ℹ [COMPILE] Compact compiler started + * ℹ [COMPILE] COMPACT_HOME: /path/to/compactc + * ℹ [COMPILE] COMPACTC_PATH: /path/to/compactc/compactc + * ℹ [COMPILE] Found 1 .compact file(s) to compile + * ✔ [COMPILE] [1/1] Compiled Foo.compact + * Compactc version: 0.22.0 + * ``` + */ +async function runCompiler(): Promise { + const spinner = ora(chalk.blue('[COMPILE] Compact Compiler started')).info(); + + try { + const compilerFlags = process.argv.slice(2).join(' '); + const compiler = new CompactCompiler(compilerFlags); + await compiler.compile(); + } catch (err) { + spinner.fail( + chalk.red('[COMPILE] Unexpected error:', (err as Error).message), + ); + process.exit(1); + } +} + +runCompiler(); diff --git a/compact/src/types/errors.ts b/compact/src/types/errors.ts new file mode 100644 index 00000000..fd651ddb --- /dev/null +++ b/compact/src/types/errors.ts @@ -0,0 +1,28 @@ +/** + * A custom error that describes the shape of an error returned from a promisfied + * child_process.exec + * + * @interface PromisifiedChildProcessError + * @typedef {PromisifiedChildProcessError} + * @extends {Error} + * + * @prop {string} stdout stdout of a child process + * @prop {string} stderr stderr of a child process + */ +export interface PromisifiedChildProcessError extends Error { + stdout: string; + stderr: string; +} + +/** + * A type guard function for PromisifiedChildProcessError + * + * @param {unknown} error - An error caught in a try catch block + * @returns {error is PromisifiedChildProcessError} - Informs TS compiler if the understood + * type is a PromisifiedChildProcessError + */ +export function isPromisifiedChildProcessError( + error: unknown, +): error is PromisifiedChildProcessError { + return error instanceof Error && 'stdout' in error && 'stderr' in error; +} diff --git a/compact/tsconfig.json b/compact/tsconfig.json new file mode 100644 index 00000000..9c283308 --- /dev/null +++ b/compact/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "declaration": true, + "lib": ["es2023"], + "module": "nodenext", + "target": "es2022", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "moduleResolution": "node16", + "sourceMap": true, + "rewriteRelativeImportExtensions": true, + "erasableSyntaxOnly": true, + "verbatimModuleSyntax": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} diff --git a/contracts/erc721/src/test/utils/index.ts b/contracts/erc721/src/test/utils/index.ts deleted file mode 100644 index 731fe1ec..00000000 --- a/contracts/erc721/src/test/utils/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { useCircuitContext as circuitContext } from './test'; -export * from './address'; diff --git a/contracts/utils/package.json b/contracts/utils/package.json index f5a0217c..f8333f63 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -13,10 +13,9 @@ } }, "scripts": { - "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", + "compact": "npx compact-compiler", + "build": "npx compact-builder && tsc", "test": "NODE_OPTIONS=--experimental-vm-modules jest", - "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/{Initializable,Pausable,Utils}.compact ./dist", - "typecheck": "tsc -p tsconfig.json --noEmit", "types": "tsc -p tsconfig.json --noEmit", "fmt": "biome format", "fmt:fix": "biome format --write", @@ -28,8 +27,9 @@ "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" }, "devDependencies": { - "@midnight-ntwrk/compact": "workspace:*", - "jest": "^29.7.0", + "@openzeppelin-midnight/compact": "workspace:^", + "@biomejs/biome": "1.9.4", + "@types/node": "^18.18.6", "typescript": "^5.2.2" } } diff --git a/contracts/utils/src/test/utils/index.ts b/contracts/utils/src/test/utils/index.ts deleted file mode 100644 index b8e9585d..00000000 --- a/contracts/utils/src/test/utils/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -export { useCircuitContext as circuitContext } from './test'; -export { - pad, - encodeToPK, - encodeToAddress, - createEitherTestUser, - createEitherTestContractAddress, - ZERO_KEY, - ZERO_ADDRESS, -} from './address'; diff --git a/package.json b/package.json index 93bbacc3..eef2ac9b 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "packageManager": "yarn@4.1.0", "workspaces": [ - "compact", - "contracts/erc20/", - "contracts/utils/" + "compact/", + "contracts/*/" ], "scripts": { + "prepare": "npx tsc -p ./compact && yarn rebuild", "compact": "turbo run compact", "build": "turbo run build", "test": "turbo run test", diff --git a/yarn.lock b/yarn.lock index 4b43ba7e..0bb1b54d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26,7 +26,7 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.26.5": +"@babel/compat-data@npm:^7.26.8": version: 7.26.8 resolution: "@babel/compat-data@npm:7.26.8" checksum: 10/bdddf577f670e0e12996ef37e134856c8061032edb71a13418c3d4dae8135da28910b7cd6dec6e668ab3a41e42089ef7ee9c54ef52fe0860b54cb420b0d14948 @@ -34,51 +34,51 @@ __metadata: linkType: hard "@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.23.9": - version: 7.26.9 - resolution: "@babel/core@npm:7.26.9" + version: 7.26.10 + resolution: "@babel/core@npm:7.26.10" dependencies: "@ampproject/remapping": "npm:^2.2.0" "@babel/code-frame": "npm:^7.26.2" - "@babel/generator": "npm:^7.26.9" + "@babel/generator": "npm:^7.26.10" "@babel/helper-compilation-targets": "npm:^7.26.5" "@babel/helper-module-transforms": "npm:^7.26.0" - "@babel/helpers": "npm:^7.26.9" - "@babel/parser": "npm:^7.26.9" + "@babel/helpers": "npm:^7.26.10" + "@babel/parser": "npm:^7.26.10" "@babel/template": "npm:^7.26.9" - "@babel/traverse": "npm:^7.26.9" - "@babel/types": "npm:^7.26.9" + "@babel/traverse": "npm:^7.26.10" + "@babel/types": "npm:^7.26.10" convert-source-map: "npm:^2.0.0" debug: "npm:^4.1.0" gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.3" semver: "npm:^6.3.1" - checksum: 10/ceed199dbe25f286a0a59a2ea7879aed37c1f3bb289375d061eda4752cab2ba365e7f9e969c7fd3b9b95c930493db6eeb5a6d6f017dd135fb5a4503449aad753 + checksum: 10/68f6707eebd6bb8beed7ceccf5153e35b86c323e40d11d796d75c626ac8f1cc4e1f795584c5ab5f886bc64150c22d5088123d68c069c63f29984c4fc054d1dab languageName: node linkType: hard -"@babel/generator@npm:^7.26.9, @babel/generator@npm:^7.7.2": - version: 7.26.9 - resolution: "@babel/generator@npm:7.26.9" +"@babel/generator@npm:^7.26.10, @babel/generator@npm:^7.27.0, @babel/generator@npm:^7.7.2": + version: 7.27.0 + resolution: "@babel/generator@npm:7.27.0" dependencies: - "@babel/parser": "npm:^7.26.9" - "@babel/types": "npm:^7.26.9" + "@babel/parser": "npm:^7.27.0" + "@babel/types": "npm:^7.27.0" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^3.0.2" - checksum: 10/95075dd6158a49efcc71d7f2c5d20194fcf245348de7723ca35e37cd5800587f1d4de2be6c4ba87b5f5fbb967c052543c109eaab14b43f6a73eb05ccd9a5bb44 + checksum: 10/5447c402b1d841132534a0a9715e89f4f28b6f2886a23e70aaa442150dba4a1e29e4e2351814f439ee1775294dccdef9ab0a4192b6e6a5ad44e24233b3611da2 languageName: node linkType: hard "@babel/helper-compilation-targets@npm:^7.26.5": - version: 7.26.5 - resolution: "@babel/helper-compilation-targets@npm:7.26.5" + version: 7.27.0 + resolution: "@babel/helper-compilation-targets@npm:7.27.0" dependencies: - "@babel/compat-data": "npm:^7.26.5" + "@babel/compat-data": "npm:^7.26.8" "@babel/helper-validator-option": "npm:^7.25.9" browserslist: "npm:^4.24.0" lru-cache: "npm:^5.1.1" semver: "npm:^6.3.1" - checksum: 10/f3b5f0bfcd7b6adf03be1a494b269782531c6e415afab2b958c077d570371cf1bfe001c442508092c50ed3711475f244c05b8f04457d8dea9c34df2b741522bf + checksum: 10/32224b512e813fc808539b4ca7fca8c224849487c365abcef8cb8b0eea635c65375b81429f82d076e9ec1f3f3b3db1d0d56aac4d482a413f58d5ad608f912155 languageName: node linkType: hard @@ -133,24 +133,24 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.26.9": - version: 7.26.9 - resolution: "@babel/helpers@npm:7.26.9" +"@babel/helpers@npm:^7.26.10": + version: 7.27.0 + resolution: "@babel/helpers@npm:7.27.0" dependencies: - "@babel/template": "npm:^7.26.9" - "@babel/types": "npm:^7.26.9" - checksum: 10/267dfa7d04dff7720610497f466aa7b60652b7ec8dde5914527879350c9d655271e892117c5b2f0f083d92d2a8e5e2cf9832d4f98cd7fb72d78f796002af19a1 + "@babel/template": "npm:^7.27.0" + "@babel/types": "npm:^7.27.0" + checksum: 10/0dd40ba1e5ba4b72d1763bb381384585a56f21a61a19dc1b9a03381fe8e840207fdaa4da645d14dc028ad768087d41aad46347cc6573bd69d82f597f5a12dc6f languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.26.9": - version: 7.26.9 - resolution: "@babel/parser@npm:7.26.9" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.26.10, @babel/parser@npm:^7.27.0": + version: 7.27.0 + resolution: "@babel/parser@npm:7.27.0" dependencies: - "@babel/types": "npm:^7.26.9" + "@babel/types": "npm:^7.27.0" bin: parser: ./bin/babel-parser.js - checksum: 10/cb84fe3ba556d6a4360f3373cf7eb0901c46608c8d77330cc1ca021d60f5d6ebb4056a8e7f9dd0ef231923ef1fe69c87b11ce9e160d2252e089a20232a2b942b + checksum: 10/0fee9f05c6db753882ca9d10958301493443da9f6986d7020ebd7a696b35886240016899bc0b47d871aea2abcafd64632343719742e87432c8145e0ec2af2a03 languageName: node linkType: hard @@ -341,39 +341,39 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.26.9, @babel/template@npm:^7.3.3": - version: 7.26.9 - resolution: "@babel/template@npm:7.26.9" +"@babel/template@npm:^7.26.9, @babel/template@npm:^7.27.0, @babel/template@npm:^7.3.3": + version: 7.27.0 + resolution: "@babel/template@npm:7.27.0" dependencies: "@babel/code-frame": "npm:^7.26.2" - "@babel/parser": "npm:^7.26.9" - "@babel/types": "npm:^7.26.9" - checksum: 10/240288cebac95b1cc1cb045ad143365643da0470e905e11731e63280e43480785bd259924f4aea83898ef68e9fa7c176f5f2d1e8b0a059b27966e8ca0b41a1b6 + "@babel/parser": "npm:^7.27.0" + "@babel/types": "npm:^7.27.0" + checksum: 10/7159ca1daea287ad34676d45a7146675444d42c7664aca3e617abc9b1d9548c8f377f35a36bb34cf956e1d3610dcb7acfcfe890aebf81880d35f91a7bd273ee5 languageName: node linkType: hard -"@babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.9": - version: 7.26.9 - resolution: "@babel/traverse@npm:7.26.9" +"@babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.10": + version: 7.27.0 + resolution: "@babel/traverse@npm:7.27.0" dependencies: "@babel/code-frame": "npm:^7.26.2" - "@babel/generator": "npm:^7.26.9" - "@babel/parser": "npm:^7.26.9" - "@babel/template": "npm:^7.26.9" - "@babel/types": "npm:^7.26.9" + "@babel/generator": "npm:^7.27.0" + "@babel/parser": "npm:^7.27.0" + "@babel/template": "npm:^7.27.0" + "@babel/types": "npm:^7.27.0" debug: "npm:^4.3.1" globals: "npm:^11.1.0" - checksum: 10/c16a79522eafa0a7e40eb556bf1e8a3d50dbb0ff943a80f2c06cee2ec7ff87baa0c5d040a5cff574d9bcb3bed05e7d8c6f13b238a931c97267674b02c6cf45b4 + checksum: 10/b0675bc16bd87187e8b090557b0650135de56a621692ad8614b20f32621350ae0fc2e1129b73b780d64a9ed4beab46849a17f90d5267b6ae6ce09ec8412a12c7 languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.9, @babel/types@npm:^7.3.3": - version: 7.26.9 - resolution: "@babel/types@npm:7.26.9" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.10, @babel/types@npm:^7.27.0, @babel/types@npm:^7.3.3": + version: 7.27.0 + resolution: "@babel/types@npm:7.27.0" dependencies: "@babel/helper-string-parser": "npm:^7.25.9" "@babel/helper-validator-identifier": "npm:^7.25.9" - checksum: 10/11b62ea7ed64ef7e39cc9b33852c1084064c3b970ae0eaa5db659241cfb776577d1e68cbff4de438bada885d3a827b52cc0f3746112d8e1bc672bb99a8eb5b56 + checksum: 10/2c322bce107c8a534dc4a23be60d570e6a4cc7ca2e44d4f0eee08c0b626104eb7e60ab8de03463bc5da1773a2f69f1e6edec1648d648d65461d6520a7f3b0770 languageName: node linkType: hard @@ -484,73 +484,6 @@ __metadata: languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.2.0": - version: 4.4.1 - resolution: "@eslint-community/eslint-utils@npm:4.4.1" - dependencies: - eslint-visitor-keys: "npm:^3.4.3" - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: 10/ae92a11412674329b4bd38422518601ec9ceae28e251104d1cad83715da9d38e321f68c817c39b64e66d0af7d98df6f9a10ad2dc638911254b47fb8932df00ef - languageName: node - linkType: hard - -"@eslint-community/regexpp@npm:^4.6.1": - version: 4.12.1 - resolution: "@eslint-community/regexpp@npm:4.12.1" - checksum: 10/c08f1dd7dd18fbb60bdd0d85820656d1374dd898af9be7f82cb00451313402a22d5e30569c150315b4385907cdbca78c22389b2a72ab78883b3173be317620cc - languageName: node - linkType: hard - -"@eslint/eslintrc@npm:^2.1.4": - version: 2.1.4 - resolution: "@eslint/eslintrc@npm:2.1.4" - dependencies: - ajv: "npm:^6.12.4" - debug: "npm:^4.3.2" - espree: "npm:^9.6.0" - globals: "npm:^13.19.0" - ignore: "npm:^5.2.0" - import-fresh: "npm:^3.2.1" - js-yaml: "npm:^4.1.0" - minimatch: "npm:^3.1.2" - strip-json-comments: "npm:^3.1.1" - checksum: 10/7a3b14f4b40fc1a22624c3f84d9f467a3d9ea1ca6e9a372116cb92507e485260359465b58e25bcb6c9981b155416b98c9973ad9b796053fd7b3f776a6946bce8 - languageName: node - linkType: hard - -"@eslint/js@npm:8.57.1": - version: 8.57.1 - resolution: "@eslint/js@npm:8.57.1" - checksum: 10/7562b21be10c2adbfa4aa5bb2eccec2cb9ac649a3569560742202c8d1cb6c931ce634937a2f0f551e078403a1c1285d6c2c0aa345dafc986149665cd69fe8b59 - languageName: node - linkType: hard - -"@humanwhocodes/config-array@npm:^0.13.0": - version: 0.13.0 - resolution: "@humanwhocodes/config-array@npm:0.13.0" - dependencies: - "@humanwhocodes/object-schema": "npm:^2.0.3" - debug: "npm:^4.3.1" - minimatch: "npm:^3.0.5" - checksum: 10/524df31e61a85392a2433bf5d03164e03da26c03d009f27852e7dcfdafbc4a23f17f021dacf88e0a7a9fe04ca032017945d19b57a16e2676d9114c22a53a9d11 - languageName: node - linkType: hard - -"@humanwhocodes/module-importer@npm:^1.0.1": - version: 1.0.1 - resolution: "@humanwhocodes/module-importer@npm:1.0.1" - checksum: 10/e993950e346331e5a32eefb27948ecdee2a2c4ab3f072b8f566cd213ef485dd50a3ca497050608db91006f5479e43f91a439aef68d2a313bd3ded06909c7c5b3 - languageName: node - linkType: hard - -"@humanwhocodes/object-schema@npm:^2.0.3": - version: 2.0.3 - resolution: "@humanwhocodes/object-schema@npm:2.0.3" - checksum: 10/05bb99ed06c16408a45a833f03a732f59bf6184795d4efadd33238ff8699190a8c871ad1121241bb6501589a9598dc83bf25b99dcbcf41e155cdf36e35e937a3 - languageName: node - linkType: hard - "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -887,18 +820,6 @@ __metadata: languageName: node linkType: hard -"@midnight-ntwrk/compact@workspace:compact": - version: 0.0.0-use.local - resolution: "@midnight-ntwrk/compact@workspace:compact" - dependencies: - eslint: "npm:^8.52.0" - ts-node: "npm:^10.9.2" - typescript: "npm:^5.2.2" - bin: - run-compactc: src/run-compactc.cjs - languageName: unknown - linkType: soft - "@midnight-ntwrk/ledger@npm:^3.0.6": version: 3.0.6 resolution: "@midnight-ntwrk/ledger@npm:3.0.6" @@ -920,33 +841,6 @@ __metadata: languageName: node linkType: hard -"@nodelib/fs.scandir@npm:2.1.5": - version: 2.1.5 - resolution: "@nodelib/fs.scandir@npm:2.1.5" - dependencies: - "@nodelib/fs.stat": "npm:2.0.5" - run-parallel: "npm:^1.1.9" - checksum: 10/6ab2a9b8a1d67b067922c36f259e3b3dfd6b97b219c540877a4944549a4d49ea5ceba5663905ab5289682f1f3c15ff441d02f0447f620a42e1cb5e1937174d4b - languageName: node - linkType: hard - -"@nodelib/fs.stat@npm:2.0.5": - version: 2.0.5 - resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 10/012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 - languageName: node - linkType: hard - -"@nodelib/fs.walk@npm:^1.2.8": - version: 1.2.8 - resolution: "@nodelib/fs.walk@npm:1.2.8" - dependencies: - "@nodelib/fs.scandir": "npm:2.1.5" - fastq: "npm:^1.6.0" - checksum: 10/40033e33e96e97d77fba5a238e4bba4487b8284678906a9f616b5579ddaf868a18874c0054a75402c9fbaaa033a25ceae093af58c9c30278e35c23c9479e79b0 - languageName: node - linkType: hard - "@npmcli/agent@npm:^3.0.0": version: 3.0.0 resolution: "@npmcli/agent@npm:3.0.0" @@ -969,17 +863,49 @@ __metadata: languageName: node linkType: hard +"@openzeppelin-midnight/compact@workspace:^, @openzeppelin-midnight/compact@workspace:compact": + version: 0.0.0-use.local + resolution: "@openzeppelin-midnight/compact@workspace:compact" + dependencies: + "@types/jest": "npm:^29.5.6" + "@types/node": "npm:^22.13.10" + chalk: "npm:^5.4.1" + fast-check: "npm:^3.15.0" + jest: "npm:^29.7.0" + jest-fast-check: "npm:^2.0.0" + log-symbols: "npm:^7.0.0" + ora: "npm:^8.2.0" + ts-jest: "npm:^29.1.1" + typescript: "npm:^5.8.2" + bin: + compact-builder: dist/runBuilder.js + compact-compiler: dist/runCompiler.js + languageName: unknown + linkType: soft + "@openzeppelin-midnight/erc20@workspace:contracts/erc20": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/erc20@workspace:contracts/erc20" dependencies: - "@openzeppelin-midnight/utils": "workspace:^" + "@biomejs/biome": "npm:1.9.4" + "@openzeppelin-midnight/compact": "workspace:^" + "@types/jest": "npm:^29.5.6" + "@types/node": "npm:^18.18.6" + jest: "npm:^29.7.0" + typescript: "npm:^5.2.2" languageName: unknown linkType: soft -"@openzeppelin-midnight/utils@workspace:^, @openzeppelin-midnight/utils@workspace:contracts/utils": +"@openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" + dependencies: + "@biomejs/biome": "npm:1.9.4" + "@openzeppelin-midnight/compact": "workspace:^" + "@types/jest": "npm:^29.5.6" + "@types/node": "npm:^18.18.6" + jest: "npm:^29.7.0" + typescript: "npm:^5.2.2" languageName: unknown linkType: soft @@ -1057,11 +983,11 @@ __metadata: linkType: hard "@types/babel__generator@npm:*": - version: 7.6.8 - resolution: "@types/babel__generator@npm:7.6.8" + version: 7.27.0 + resolution: "@types/babel__generator@npm:7.27.0" dependencies: "@babel/types": "npm:^7.0.0" - checksum: 10/b53c215e9074c69d212402990b0ca8fa57595d09e10d94bda3130aa22b55d796e50449199867879e4ea0ee968f3a2099e009cfb21a726a53324483abbf25cd30 + checksum: 10/f572e67a9a39397664350a4437d8a7fbd34acc83ff4887a8cf08349e39f8aeb5ad2f70fb78a0a0a23a280affe3a5f4c25f50966abdce292bcf31237af1c27b1a languageName: node linkType: hard @@ -1076,11 +1002,11 @@ __metadata: linkType: hard "@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6": - version: 7.20.6 - resolution: "@types/babel__traverse@npm:7.20.6" + version: 7.20.7 + resolution: "@types/babel__traverse@npm:7.20.7" dependencies: "@babel/types": "npm:^7.20.7" - checksum: 10/63d13a3789aa1e783b87a8b03d9fb2c2c90078de7782422feff1631b8c2a25db626e63a63ac5a1465d47359201c73069dacb4b52149d17c568187625da3064ae + checksum: 10/d005b58e1c26bdafc1ce564f60db0ee938393c7fc586b1197bdb71a02f7f33f72bc10ae4165776b6cafc77c4b6f2e1a164dd20bc36518c471b1131b153b4baa6 languageName: node linkType: hard @@ -1128,21 +1054,21 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*": - version: 22.13.8 - resolution: "@types/node@npm:22.13.8" +"@types/node@npm:*, @types/node@npm:^22.13.10": + version: 22.15.2 + resolution: "@types/node@npm:22.15.2" dependencies: - undici-types: "npm:~6.20.0" - checksum: 10/b69de3caab80336747bf41b5063478d23b196b9594c6f2eb819791380cc571676087dceb0fde9531ef7a1293f3eae12a9aaf79d8de349378c29a17c5e657bc78 + undici-types: "npm:~6.21.0" + checksum: 10/e22071571205413518aa3710644ed9603d8f4a417fc59f0e180240e1c05aaf7fb8feecdf553a2da305247b3533d03b58eab6e333115f01f581b9139a6b1dcd47 languageName: node linkType: hard "@types/node@npm:^18.18.6": - version: 18.19.78 - resolution: "@types/node@npm:18.19.78" + version: 18.19.87 + resolution: "@types/node@npm:18.19.87" dependencies: undici-types: "npm:~5.26.4" - checksum: 10/c9b285b965c054d4ffd511fd31c18b3d1512dfdf2af0f0340b19a225716aedc2a26d87dadc2dd27b33e2fa6cbcdacff2bb8bf70f91978b2ef3b18dfa327afdfb + checksum: 10/1e71b6d16dedeaa1fd5ff55baf1f353ca1f9e673b2e482d7fe82fa685addea5159a36602a344784c989b5e07ca1be633d0c493adf5951dee5a29cee69d613e7f languageName: node linkType: hard @@ -1176,26 +1102,10 @@ __metadata: languageName: node linkType: hard -"@ungap/structured-clone@npm:^1.2.0": - version: 1.3.0 - resolution: "@ungap/structured-clone@npm:1.3.0" - checksum: 10/80d6910946f2b1552a2406650051c91bbd1f24a6bf854354203d84fe2714b3e8ce4618f49cc3410494173a1c1e8e9777372fe68dce74bd45faf0a7a1a6ccf448 - languageName: node - linkType: hard - "abbrev@npm:^3.0.0": - version: 3.0.0 - resolution: "abbrev@npm:3.0.0" - checksum: 10/2ceee14efdeda42ef7355178c1069499f183546ff7112b3efe79c1edef09d20ad9c17939752215fb8f7fcf48d10e6a7c0aa00136dc9cf4d293d963718bb1d200 - languageName: node - linkType: hard - -"acorn-jsx@npm:^5.3.2": - version: 5.3.2 - resolution: "acorn-jsx@npm:5.3.2" - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 10/d4371eaef7995530b5b5ca4183ff6f062ca17901a6d3f673c9ac011b01ede37e7a1f7f61f8f5cfe709e88054757bb8f3277dc4061087cdf4f2a1f90ccbcdb977 + version: 3.0.1 + resolution: "abbrev@npm:3.0.1" + checksum: 10/ebd2c149dda6f543b66ce3779ea612151bb3aa9d0824f169773ee9876f1ca5a4e0adbcccc7eed048c04da7998e1825e2aa76fcca92d9e67dea50ac2b0a58dc2e languageName: node linkType: hard @@ -1208,12 +1118,12 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.11.0, acorn@npm:^8.4.1, acorn@npm:^8.9.0": - version: 8.14.0 - resolution: "acorn@npm:8.14.0" +"acorn@npm:^8.11.0, acorn@npm:^8.4.1": + version: 8.14.1 + resolution: "acorn@npm:8.14.1" bin: acorn: bin/acorn - checksum: 10/6df29c35556782ca9e632db461a7f97947772c6c1d5438a81f0c873a3da3a792487e83e404d1c6c25f70513e91aa18745f6eafb1fcc3a43ecd1920b21dd173d2 + checksum: 10/d1379bbee224e8d44c3c3946e6ba6973e999fbdd4e22e41c3455d7f9b6f72f7ce18d3dc218002e1e48eea789539cf1cb6d1430c81838c6744799c712fb557d92 languageName: node linkType: hard @@ -1224,18 +1134,6 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.12.4": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" - dependencies: - fast-deep-equal: "npm:^3.1.1" - fast-json-stable-stringify: "npm:^2.0.0" - json-schema-traverse: "npm:^0.4.1" - uri-js: "npm:^4.2.2" - checksum: 10/48d6ad21138d12eb4d16d878d630079a2bda25a04e745c07846a4ad768319533031e28872a9b3c5790fa1ec41aabdf2abed30a56e5a03ebc2cf92184b8ee306c - languageName: node - linkType: hard - "ansi-escapes@npm:^4.2.1": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" @@ -1308,13 +1206,6 @@ __metadata: languageName: node linkType: hard -"argparse@npm:^2.0.1": - version: 2.0.1 - resolution: "argparse@npm:2.0.1" - checksum: 10/18640244e641a417ec75a9bd38b0b2b6b95af5199aa241b131d4b2fb206f334d7ecc600bd194861610a5579084978bfcbb02baa399dbe442d56d0ae5e60dbaef - languageName: node - linkType: hard - "async@npm:^3.2.3": version: 3.2.6 resolution: "async@npm:3.2.6" @@ -1517,9 +1408,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001688": - version: 1.0.30001701 - resolution: "caniuse-lite@npm:1.0.30001701" - checksum: 10/d121607a96f9165128203a317d6aee6a4c7808d52a1f3b46ef5fb918abe9e9d4463e57b0bd5ffe2f4316292bd5b8d85a832b4456b7ca6f024f377b498911bfec + version: 1.0.30001715 + resolution: "caniuse-lite@npm:1.0.30001715" + checksum: 10/5608cdaf609eb5fe3a86ab6c1c2f3943dbdab813041725f4747f5432b05e6e19fc606faa8a9b75c329b37b772c91c47e8db483e76a6b715b59c289ce53dcba68 languageName: node linkType: hard @@ -1533,6 +1424,13 @@ __metadata: languageName: node linkType: hard +"chalk@npm:^5.3.0, chalk@npm:^5.4.1": + version: 5.4.1 + resolution: "chalk@npm:5.4.1" + checksum: 10/29df3ffcdf25656fed6e95962e2ef86d14dfe03cd50e7074b06bad9ffbbf6089adbb40f75c00744d843685c8d008adaf3aed31476780312553caf07fa86e5bc7 + languageName: node + linkType: hard + "char-regex@npm:^1.0.2": version: 1.0.2 resolution: "char-regex@npm:1.0.2" @@ -1561,6 +1459,22 @@ __metadata: languageName: node linkType: hard +"cli-cursor@npm:^5.0.0": + version: 5.0.0 + resolution: "cli-cursor@npm:5.0.0" + dependencies: + restore-cursor: "npm:^5.0.0" + checksum: 10/1eb9a3f878b31addfe8d82c6d915ec2330cec8447ab1f117f4aa34f0137fbb3137ec3466e1c9a65bcb7557f6e486d343f2da57f253a2f668d691372dfa15c090 + languageName: node + linkType: hard + +"cli-spinners@npm:^2.9.2": + version: 2.9.2 + resolution: "cli-spinners@npm:2.9.2" + checksum: 10/a0a863f442df35ed7294424f5491fa1756bd8d2e4ff0c8736531d886cec0ece4d85e8663b77a5afaf1d296e3cbbebff92e2e99f52bbea89b667cbe789b994794 + languageName: node + linkType: hard + "cliui@npm:^8.0.1": version: 8.0.1 resolution: "cliui@npm:8.0.1" @@ -1640,7 +1554,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": +"cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -1651,7 +1565,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.4": version: 4.4.0 resolution: "debug@npm:4.4.0" dependencies: @@ -1675,13 +1589,6 @@ __metadata: languageName: node linkType: hard -"deep-is@npm:^0.1.3": - version: 0.1.4 - resolution: "deep-is@npm:0.1.4" - checksum: 10/ec12d074aef5ae5e81fa470b9317c313142c9e8e2afe3f8efa124db309720db96d1d222b82b84c834e5f87e7a614b44a4684b6683583118b87c833b3be40d4d8 - languageName: node - linkType: hard - "deepmerge@npm:^4.2.2": version: 4.3.1 resolution: "deepmerge@npm:4.3.1" @@ -1710,15 +1617,6 @@ __metadata: languageName: node linkType: hard -"doctrine@npm:^3.0.0": - version: 3.0.0 - resolution: "doctrine@npm:3.0.0" - dependencies: - esutils: "npm:^2.0.2" - checksum: 10/b4b28f1df5c563f7d876e7461254a4597b8cabe915abe94d7c5d1633fed263fcf9a85e8d3836591fc2d040108e822b0d32758e5ec1fe31c590dc7e08086e3e48 - languageName: node - linkType: hard - "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -1738,9 +1636,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.5.73": - version: 1.5.109 - resolution: "electron-to-chromium@npm:1.5.109" - checksum: 10/4f6bd5963a2a55cbff97b2374cb0dbd6141f85e5cf8cb07267d91b0e56f3a4c8df72a7be905ddb1770b9277deef207567e97f94b9385c7cba3775620af17a932 + version: 1.5.143 + resolution: "electron-to-chromium@npm:1.5.143" + checksum: 10/91a7980f96da5ad33b77e95c7e628f468e6bb53eac41437612882810a7552514132728f7c34ee5c967c599557af491fcc4f75e9138f82d22c1b1cdfc63fb8d6b languageName: node linkType: hard @@ -1751,6 +1649,13 @@ __metadata: languageName: node linkType: hard +"emoji-regex@npm:^10.3.0": + version: 10.4.0 + resolution: "emoji-regex@npm:10.4.0" + checksum: 10/76bb92c5bcf0b6980d37e535156231e4a9d0aa6ab3b9f5eabf7690231d5aa5d5b8e516f36e6804cbdd0f1c23dfef2a60c40ab7bb8aedd890584281a565b97c50 + languageName: node + linkType: hard + "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -1811,89 +1716,6 @@ __metadata: languageName: node linkType: hard -"escape-string-regexp@npm:^4.0.0": - version: 4.0.0 - resolution: "escape-string-regexp@npm:4.0.0" - checksum: 10/98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5 - languageName: node - linkType: hard - -"eslint-scope@npm:^7.2.2": - version: 7.2.2 - resolution: "eslint-scope@npm:7.2.2" - dependencies: - esrecurse: "npm:^4.3.0" - estraverse: "npm:^5.2.0" - checksum: 10/5c660fb905d5883ad018a6fea2b49f3cb5b1cbf2cd4bd08e98646e9864f9bc2c74c0839bed2d292e90a4a328833accc197c8f0baed89cbe8d605d6f918465491 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": - version: 3.4.3 - resolution: "eslint-visitor-keys@npm:3.4.3" - checksum: 10/3f357c554a9ea794b094a09bd4187e5eacd1bc0d0653c3adeb87962c548e6a1ab8f982b86963ae1337f5d976004146536dcee5d0e2806665b193fbfbf1a9231b - languageName: node - linkType: hard - -"eslint@npm:^8.52.0": - version: 8.57.1 - resolution: "eslint@npm:8.57.1" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.2.0" - "@eslint-community/regexpp": "npm:^4.6.1" - "@eslint/eslintrc": "npm:^2.1.4" - "@eslint/js": "npm:8.57.1" - "@humanwhocodes/config-array": "npm:^0.13.0" - "@humanwhocodes/module-importer": "npm:^1.0.1" - "@nodelib/fs.walk": "npm:^1.2.8" - "@ungap/structured-clone": "npm:^1.2.0" - ajv: "npm:^6.12.4" - chalk: "npm:^4.0.0" - cross-spawn: "npm:^7.0.2" - debug: "npm:^4.3.2" - doctrine: "npm:^3.0.0" - escape-string-regexp: "npm:^4.0.0" - eslint-scope: "npm:^7.2.2" - eslint-visitor-keys: "npm:^3.4.3" - espree: "npm:^9.6.1" - esquery: "npm:^1.4.2" - esutils: "npm:^2.0.2" - fast-deep-equal: "npm:^3.1.3" - file-entry-cache: "npm:^6.0.1" - find-up: "npm:^5.0.0" - glob-parent: "npm:^6.0.2" - globals: "npm:^13.19.0" - graphemer: "npm:^1.4.0" - ignore: "npm:^5.2.0" - imurmurhash: "npm:^0.1.4" - is-glob: "npm:^4.0.0" - is-path-inside: "npm:^3.0.3" - js-yaml: "npm:^4.1.0" - json-stable-stringify-without-jsonify: "npm:^1.0.1" - levn: "npm:^0.4.1" - lodash.merge: "npm:^4.6.2" - minimatch: "npm:^3.1.2" - natural-compare: "npm:^1.4.0" - optionator: "npm:^0.9.3" - strip-ansi: "npm:^6.0.1" - text-table: "npm:^0.2.0" - bin: - eslint: bin/eslint.js - checksum: 10/5504fa24879afdd9f9929b2fbfc2ee9b9441a3d464efd9790fbda5f05738858530182029f13323add68d19fec749d3ab4a70320ded091ca4432b1e9cc4ed104c - languageName: node - linkType: hard - -"espree@npm:^9.6.0, espree@npm:^9.6.1": - version: 9.6.1 - resolution: "espree@npm:9.6.1" - dependencies: - acorn: "npm:^8.9.0" - acorn-jsx: "npm:^5.3.2" - eslint-visitor-keys: "npm:^3.4.1" - checksum: 10/255ab260f0d711a54096bdeda93adff0eadf02a6f9b92f02b323e83a2b7fc258797919437ad331efec3930475feb0142c5ecaaf3cdab4befebd336d47d3f3134 - languageName: node - linkType: hard - "esprima@npm:^4.0.0": version: 4.0.1 resolution: "esprima@npm:4.0.1" @@ -1904,38 +1726,6 @@ __metadata: languageName: node linkType: hard -"esquery@npm:^1.4.2": - version: 1.6.0 - resolution: "esquery@npm:1.6.0" - dependencies: - estraverse: "npm:^5.1.0" - checksum: 10/c587fb8ec9ed83f2b1bc97cf2f6854cc30bf784a79d62ba08c6e358bf22280d69aee12827521cf38e69ae9761d23fb7fde593ce315610f85655c139d99b05e5a - languageName: node - linkType: hard - -"esrecurse@npm:^4.3.0": - version: 4.3.0 - resolution: "esrecurse@npm:4.3.0" - dependencies: - estraverse: "npm:^5.2.0" - checksum: 10/44ffcd89e714ea6b30143e7f119b104fc4d75e77ee913f34d59076b40ef2d21967f84e019f84e1fd0465b42cdbf725db449f232b5e47f29df29ed76194db8e16 - languageName: node - linkType: hard - -"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": - version: 5.3.0 - resolution: "estraverse@npm:5.3.0" - checksum: 10/37cbe6e9a68014d34dbdc039f90d0baf72436809d02edffcc06ba3c2a12eb298048f877511353b130153e532aac8d68ba78430c0dd2f44806ebc7c014b01585e - languageName: node - linkType: hard - -"esutils@npm:^2.0.2": - version: 2.0.3 - resolution: "esutils@npm:2.0.3" - checksum: 10/b23acd24791db11d8f65be5ea58fd9a6ce2df5120ae2da65c16cfc5331ff59d5ac4ef50af66cd4bde238881503ec839928a0135b99a036a9cdfa22d17fd56cdb - languageName: node - linkType: hard - "execa@npm:^5.0.0": version: 5.1.1 resolution: "execa@npm:5.1.1" @@ -1989,36 +1779,13 @@ __metadata: languageName: node linkType: hard -"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": - version: 3.1.3 - resolution: "fast-deep-equal@npm:3.1.3" - checksum: 10/e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d - languageName: node - linkType: hard - -"fast-json-stable-stringify@npm:2.x, fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0": +"fast-json-stable-stringify@npm:2.x, fast-json-stable-stringify@npm:^2.1.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" checksum: 10/2c20055c1fa43c922428f16ca8bb29f2807de63e5c851f665f7ac9790176c01c3b40335257736b299764a8d383388dabc73c8083b8e1bc3d99f0a941444ec60e languageName: node linkType: hard -"fast-levenshtein@npm:^2.0.6": - version: 2.0.6 - resolution: "fast-levenshtein@npm:2.0.6" - checksum: 10/eb7e220ecf2bab5159d157350b81d01f75726a4382f5a9266f42b9150c4523b9795f7f5d9fbbbeaeac09a441b2369f05ee02db48ea938584205530fe5693cfe1 - languageName: node - linkType: hard - -"fastq@npm:^1.6.0": - version: 1.19.1 - resolution: "fastq@npm:1.19.1" - dependencies: - reusify: "npm:^1.0.4" - checksum: 10/75679dc226316341c4f2a6b618571f51eac96779906faecd8921b984e844d6ae42fabb2df69b1071327d398d5716693ea9c9c8941f64ac9e89ec2032ce59d730 - languageName: node - linkType: hard - "fb-watchman@npm:^2.0.0": version: 2.0.2 resolution: "fb-watchman@npm:2.0.2" @@ -2028,12 +1795,15 @@ __metadata: languageName: node linkType: hard -"file-entry-cache@npm:^6.0.1": - version: 6.0.1 - resolution: "file-entry-cache@npm:6.0.1" - dependencies: - flat-cache: "npm:^3.0.4" - checksum: 10/099bb9d4ab332cb93c48b14807a6918a1da87c45dce91d4b61fd40e6505d56d0697da060cb901c729c90487067d93c9243f5da3dc9c41f0358483bfdebca736b +"fdir@npm:^6.4.4": + version: 6.4.4 + resolution: "fdir@npm:6.4.4" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10/d0000d6b790059b35f4ed19acc8847a66452e0bc68b28766c929ffd523e5ec2083811fc8a545e4a1d4945ce70e887b3a610c145c681073b506143ae3076342ed languageName: node linkType: hard @@ -2065,34 +1835,6 @@ __metadata: languageName: node linkType: hard -"find-up@npm:^5.0.0": - version: 5.0.0 - resolution: "find-up@npm:5.0.0" - dependencies: - locate-path: "npm:^6.0.0" - path-exists: "npm:^4.0.0" - checksum: 10/07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095 - languageName: node - linkType: hard - -"flat-cache@npm:^3.0.4": - version: 3.2.0 - resolution: "flat-cache@npm:3.2.0" - dependencies: - flatted: "npm:^3.2.9" - keyv: "npm:^4.5.3" - rimraf: "npm:^3.0.2" - checksum: 10/02381c6ece5e9fa5b826c9bbea481d7fd77645d96e4b0b1395238124d581d10e56f17f723d897b6d133970f7a57f0fab9148cbbb67237a0a0ffe794ba60c0c70 - languageName: node - linkType: hard - -"flatted@npm:^3.2.9": - version: 3.3.3 - resolution: "flatted@npm:3.3.3" - checksum: 10/8c96c02fbeadcf4e8ffd0fa24983241e27698b0781295622591fc13585e2f226609d95e422bcf2ef044146ffacb6b68b1f20871454eddf75ab3caa6ee5f4a1fe - languageName: node - linkType: hard - "foreground-child@npm:^3.1.0": version: 3.3.1 resolution: "foreground-child@npm:3.3.1" @@ -2159,6 +1901,13 @@ __metadata: languageName: node linkType: hard +"get-east-asian-width@npm:^1.0.0": + version: 1.3.0 + resolution: "get-east-asian-width@npm:1.3.0" + checksum: 10/8e8e779eb28701db7fdb1c8cab879e39e6ae23f52dadd89c8aed05869671cee611a65d4f8557b83e981428623247d8bc5d0c7a4ef3ea7a41d826e73600112ad8 + languageName: node + linkType: hard + "get-package-type@npm:^0.1.0": version: 0.1.0 resolution: "get-package-type@npm:0.1.0" @@ -2173,16 +1922,7 @@ __metadata: languageName: node linkType: hard -"glob-parent@npm:^6.0.2": - version: 6.0.2 - resolution: "glob-parent@npm:6.0.2" - dependencies: - is-glob: "npm:^4.0.3" - checksum: 10/c13ee97978bef4f55106b71e66428eb1512e71a7466ba49025fc2aec59a5bfb0954d5abd58fc5ee6c9b076eef4e1f6d3375c2e964b88466ca390da4419a786a8 - languageName: node - linkType: hard - -"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7": +"glob@npm:^10.2.2": version: 10.4.5 resolution: "glob@npm:10.4.5" dependencies: @@ -2219,15 +1959,6 @@ __metadata: languageName: node linkType: hard -"globals@npm:^13.19.0": - version: 13.24.0 - resolution: "globals@npm:13.24.0" - dependencies: - type-fest: "npm:^0.20.2" - checksum: 10/62c5b1997d06674fc7191d3e01e324d3eda4d65ac9cc4e78329fa3b5c4fd42a0e1c8722822497a6964eee075255ce21ccf1eec2d83f92ef3f06653af4d0ee28e - languageName: node - linkType: hard - "graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" @@ -2235,13 +1966,6 @@ __metadata: languageName: node linkType: hard -"graphemer@npm:^1.4.0": - version: 1.4.0 - resolution: "graphemer@npm:1.4.0" - checksum: 10/6dd60dba97007b21e3a829fab3f771803cc1292977fe610e240ea72afd67e5690ac9eeaafc4a99710e78962e5936ab5a460787c2a1180f1cb0ccfac37d29f897 - languageName: node - linkType: hard - "has-flag@npm:^4.0.0": version: 4.0.0 resolution: "has-flag@npm:4.0.0" @@ -2308,23 +2032,6 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.2.0": - version: 5.3.2 - resolution: "ignore@npm:5.3.2" - checksum: 10/cceb6a457000f8f6a50e1196429750d782afce5680dd878aa4221bd79972d68b3a55b4b1458fc682be978f4d3c6a249046aa0880637367216444ab7b014cfc98 - languageName: node - linkType: hard - -"import-fresh@npm:^3.2.1": - version: 3.3.1 - resolution: "import-fresh@npm:3.3.1" - dependencies: - parent-module: "npm:^1.0.0" - resolve-from: "npm:^4.0.0" - checksum: 10/a06b19461b4879cc654d46f8a6244eb55eb053437afd4cbb6613cad6be203811849ed3e4ea038783092879487299fda24af932b86bdfff67c9055ba3612b8c87 - languageName: node - linkType: hard - "import-local@npm:^3.0.2": version: 3.2.0 resolution: "import-local@npm:3.2.0" @@ -2387,13 +2094,6 @@ __metadata: languageName: node linkType: hard -"is-extglob@npm:^2.1.1": - version: 2.1.1 - resolution: "is-extglob@npm:2.1.1" - checksum: 10/df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 - languageName: node - linkType: hard - "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -2408,12 +2108,10 @@ __metadata: languageName: node linkType: hard -"is-glob@npm:^4.0.0, is-glob@npm:^4.0.3": - version: 4.0.3 - resolution: "is-glob@npm:4.0.3" - dependencies: - is-extglob: "npm:^2.1.1" - checksum: 10/3ed74f2b0cdf4f401f38edb0442ddfde3092d79d7d35c9919c86641efdbcbb32e45aa3c0f70ce5eecc946896cd5a0f26e4188b9f2b881876f7cb6c505b82da11 +"is-interactive@npm:^2.0.0": + version: 2.0.0 + resolution: "is-interactive@npm:2.0.0" + checksum: 10/e8d52ad490bed7ae665032c7675ec07732bbfe25808b0efbc4d5a76b1a1f01c165f332775c63e25e9a03d319ebb6b24f571a9e902669fc1e40b0a60b5be6e26c languageName: node linkType: hard @@ -2424,13 +2122,6 @@ __metadata: languageName: node linkType: hard -"is-path-inside@npm:^3.0.3": - version: 3.0.3 - resolution: "is-path-inside@npm:3.0.3" - checksum: 10/abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 - languageName: node - linkType: hard - "is-stream@npm:^2.0.0": version: 2.0.1 resolution: "is-stream@npm:2.0.1" @@ -2438,6 +2129,20 @@ __metadata: languageName: node linkType: hard +"is-unicode-supported@npm:^1.3.0": + version: 1.3.0 + resolution: "is-unicode-supported@npm:1.3.0" + checksum: 10/20a1fc161afafaf49243551a5ac33b6c4cf0bbcce369fcd8f2951fbdd000c30698ce320de3ee6830497310a8f41880f8066d440aa3eb0a853e2aa4836dd89abc + languageName: node + linkType: hard + +"is-unicode-supported@npm:^2.0.0": + version: 2.1.0 + resolution: "is-unicode-supported@npm:2.1.0" + checksum: 10/f254e3da6b0ab1a57a94f7273a7798dd35d1d45b227759f600d0fa9d5649f9c07fa8d3c8a6360b0e376adf916d151ec24fc9a50c5295c58bae7ca54a76a063f9 + languageName: node + linkType: hard + "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -3012,17 +2717,6 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^4.1.0": - version: 4.1.0 - resolution: "js-yaml@npm:4.1.0" - dependencies: - argparse: "npm:^2.0.1" - bin: - js-yaml: bin/js-yaml.js - checksum: 10/c138a34a3fd0d08ebaf71273ad4465569a483b8a639e0b118ff65698d257c2791d3199e3f303631f2cb98213fa7b5f5d6a4621fd0fff819421b990d30d967140 - languageName: node - linkType: hard - "jsbn@npm:1.1.0": version: 1.1.0 resolution: "jsbn@npm:1.1.0" @@ -3039,13 +2733,6 @@ __metadata: languageName: node linkType: hard -"json-buffer@npm:3.0.1": - version: 3.0.1 - resolution: "json-buffer@npm:3.0.1" - checksum: 10/82876154521b7b68ba71c4f969b91572d1beabadd87bd3a6b236f85fbc7dc4695089191ed60bb59f9340993c51b33d479f45b6ba9f3548beb519705281c32c3c - languageName: node - linkType: hard - "json-parse-even-better-errors@npm:^2.3.0": version: 2.3.1 resolution: "json-parse-even-better-errors@npm:2.3.1" @@ -3053,20 +2740,6 @@ __metadata: languageName: node linkType: hard -"json-schema-traverse@npm:^0.4.1": - version: 0.4.1 - resolution: "json-schema-traverse@npm:0.4.1" - checksum: 10/7486074d3ba247769fda17d5181b345c9fb7d12e0da98b22d1d71a5db9698d8b4bd900a3ec1a4ffdd60846fc2556274a5c894d0c48795f14cb03aeae7b55260b - languageName: node - linkType: hard - -"json-stable-stringify-without-jsonify@npm:^1.0.1": - version: 1.0.1 - resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" - checksum: 10/12786c2e2f22c27439e6db0532ba321f1d0617c27ad8cb1c352a0e9249a50182fd1ba8b52a18899291604b0c32eafa8afd09e51203f19109a0537f68db2b652d - languageName: node - linkType: hard - "json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" @@ -3076,15 +2749,6 @@ __metadata: languageName: node linkType: hard -"keyv@npm:^4.5.3": - version: 4.5.4 - resolution: "keyv@npm:4.5.4" - dependencies: - json-buffer: "npm:3.0.1" - checksum: 10/167eb6ef64cc84b6fa0780ee50c9de456b422a1e18802209234f7c2cf7eae648c7741f32e50d7e24ccb22b24c13154070b01563d642755b156c357431a191e75 - languageName: node - linkType: hard - "kleur@npm:^3.0.3": version: 3.0.3 resolution: "kleur@npm:3.0.3" @@ -3099,16 +2763,6 @@ __metadata: languageName: node linkType: hard -"levn@npm:^0.4.1": - version: 0.4.1 - resolution: "levn@npm:0.4.1" - dependencies: - prelude-ls: "npm:^1.2.1" - type-check: "npm:~0.4.0" - checksum: 10/2e4720ff79f21ae08d42374b0a5c2f664c5be8b6c8f565bb4e1315c96ed3a8acaa9de788ffed82d7f2378cf36958573de07ef92336cb5255ed74d08b8318c9ee - languageName: node - linkType: hard - "lines-and-columns@npm:^1.1.6": version: 1.2.4 resolution: "lines-and-columns@npm:1.2.4" @@ -3125,15 +2779,6 @@ __metadata: languageName: node linkType: hard -"locate-path@npm:^6.0.0": - version: 6.0.0 - resolution: "locate-path@npm:6.0.0" - dependencies: - p-locate: "npm:^5.0.0" - checksum: 10/72eb661788a0368c099a184c59d2fee760b3831c9c1c33955e8a19ae4a21b4116e53fa736dc086cdeb9fce9f7cc508f2f92d2d3aae516f133e16a2bb59a39f5a - languageName: node - linkType: hard - "lodash.memoize@npm:^4.1.2": version: 4.1.2 resolution: "lodash.memoize@npm:4.1.2" @@ -3141,10 +2786,23 @@ __metadata: languageName: node linkType: hard -"lodash.merge@npm:^4.6.2": - version: 4.6.2 - resolution: "lodash.merge@npm:4.6.2" - checksum: 10/d0ea2dd0097e6201be083865d50c3fb54fbfbdb247d9cc5950e086c991f448b7ab0cdab0d57eacccb43473d3f2acd21e134db39f22dac2d6c9ba6bf26978e3d6 +"log-symbols@npm:^6.0.0": + version: 6.0.0 + resolution: "log-symbols@npm:6.0.0" + dependencies: + chalk: "npm:^5.3.0" + is-unicode-supported: "npm:^1.3.0" + checksum: 10/510cdda36700cbcd87a2a691ea08d310a6c6b449084018f7f2ec4f732ca5e51b301ff1327aadd96f53c08318e616276c65f7fe22f2a16704fb0715d788bc3c33 + languageName: node + linkType: hard + +"log-symbols@npm:^7.0.0": + version: 7.0.0 + resolution: "log-symbols@npm:7.0.0" + dependencies: + is-unicode-supported: "npm:^2.0.0" + yoctocolors: "npm:^2.1.1" + checksum: 10/a6cb6e90bfe9f0774a09ff783e2035cd7e375a42757d7e401b391916a67f6da382f4966b57dda89430faaebe2ed13803ea867e104f8d67caf66082943a7153f0 languageName: node linkType: hard @@ -3232,7 +2890,14 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": +"mimic-function@npm:^5.0.0": + version: 5.0.1 + resolution: "mimic-function@npm:5.0.1" + checksum: 10/eb5893c99e902ccebbc267c6c6b83092966af84682957f79313311edb95e8bb5f39fb048d77132b700474d1c86d90ccc211e99bae0935447a4834eb4c882982c + languageName: node + linkType: hard + +"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -3327,12 +2992,11 @@ __metadata: linkType: hard "minizlib@npm:^3.0.1": - version: 3.0.1 - resolution: "minizlib@npm:3.0.1" + version: 3.0.2 + resolution: "minizlib@npm:3.0.2" dependencies: - minipass: "npm:^7.0.4" - rimraf: "npm:^5.0.5" - checksum: 10/622cb85f51e5c206a080a62d20db0d7b4066f308cb6ce82a9644da112367c3416ae7062017e631eb7ac8588191cfa4a9a279b8651c399265202b298e98c4acef + minipass: "npm:^7.1.2" + checksum: 10/c075bed1594f68dcc8c35122333520112daefd4d070e5d0a228bd4cf5580e9eed3981b96c0ae1d62488e204e80fd27b2b9d0068ca9a5ef3993e9565faf63ca41 languageName: node linkType: hard @@ -3367,22 +3031,22 @@ __metadata: linkType: hard "node-gyp@npm:latest": - version: 11.1.0 - resolution: "node-gyp@npm:11.1.0" + version: 11.2.0 + resolution: "node-gyp@npm:11.2.0" dependencies: env-paths: "npm:^2.2.0" exponential-backoff: "npm:^3.1.1" - glob: "npm:^10.3.10" graceful-fs: "npm:^4.2.6" make-fetch-happen: "npm:^14.0.3" nopt: "npm:^8.0.0" proc-log: "npm:^5.0.0" semver: "npm:^7.3.5" tar: "npm:^7.4.3" + tinyglobby: "npm:^0.2.12" which: "npm:^5.0.0" bin: node-gyp: bin/node-gyp.js - checksum: 10/3314ebfeb99dbcdf9e8c810df1ee52294045399873d4ab1e6740608c4fbe63adaf6580c0610b23c6eda125e298536553f5bb6fb0df714016a5c721ed31095e42 + checksum: 10/806fd8e3adc9157e17bf0d4a2c899cf6b98a0bbe9f453f630094ce791866271f6cddcaf2133e6513715d934fcba2014d287c7053d5d7934937b3a34d5a3d84ad languageName: node linkType: hard @@ -3452,17 +3116,29 @@ __metadata: languageName: node linkType: hard -"optionator@npm:^0.9.3": - version: 0.9.4 - resolution: "optionator@npm:0.9.4" +"onetime@npm:^7.0.0": + version: 7.0.0 + resolution: "onetime@npm:7.0.0" + dependencies: + mimic-function: "npm:^5.0.0" + checksum: 10/eb08d2da9339819e2f9d52cab9caf2557d80e9af8c7d1ae86e1a0fef027d00a88e9f5bd67494d350df360f7c559fbb44e800b32f310fb989c860214eacbb561c + languageName: node + linkType: hard + +"ora@npm:^8.2.0": + version: 8.2.0 + resolution: "ora@npm:8.2.0" dependencies: - deep-is: "npm:^0.1.3" - fast-levenshtein: "npm:^2.0.6" - levn: "npm:^0.4.1" - prelude-ls: "npm:^1.2.1" - type-check: "npm:^0.4.0" - word-wrap: "npm:^1.2.5" - checksum: 10/a8398559c60aef88d7f353a4f98dcdff6090a4e70f874c827302bf1213d9106a1c4d5fcb68dacb1feb3c30a04c4102f41047aa55d4c576b863d6fc876e001af6 + chalk: "npm:^5.3.0" + cli-cursor: "npm:^5.0.0" + cli-spinners: "npm:^2.9.2" + is-interactive: "npm:^2.0.0" + is-unicode-supported: "npm:^2.0.0" + log-symbols: "npm:^6.0.0" + stdin-discarder: "npm:^0.2.2" + string-width: "npm:^7.2.0" + strip-ansi: "npm:^7.1.0" + checksum: 10/cea932fdcb29549cd7b5af81f427760986429cadc752b1dd4bf31bc6821f5ba137e1ef9a18cde7bdfbe5b4e3d3201e76b048765c51a27b15d18c57ac0e0a909a languageName: node linkType: hard @@ -3475,7 +3151,7 @@ __metadata: languageName: node linkType: hard -"p-limit@npm:^3.0.2, p-limit@npm:^3.1.0": +"p-limit@npm:^3.1.0": version: 3.1.0 resolution: "p-limit@npm:3.1.0" dependencies: @@ -3493,15 +3169,6 @@ __metadata: languageName: node linkType: hard -"p-locate@npm:^5.0.0": - version: 5.0.0 - resolution: "p-locate@npm:5.0.0" - dependencies: - p-limit: "npm:^3.0.2" - checksum: 10/1623088f36cf1cbca58e9b61c4e62bf0c60a07af5ae1ca99a720837356b5b6c5ba3eb1b2127e47a06865fee59dd0453cad7cc844cda9d5a62ac1a5a51b7c86d3 - languageName: node - linkType: hard - "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" @@ -3523,15 +3190,6 @@ __metadata: languageName: node linkType: hard -"parent-module@npm:^1.0.0": - version: 1.0.1 - resolution: "parent-module@npm:1.0.1" - dependencies: - callsites: "npm:^3.0.0" - checksum: 10/6ba8b255145cae9470cf5551eb74be2d22281587af787a2626683a6c20fbb464978784661478dd2a3f1dad74d1e802d403e1b03c1a31fab310259eec8ac560ff - languageName: node - linkType: hard - "parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" @@ -3596,10 +3254,17 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.2": + version: 4.0.2 + resolution: "picomatch@npm:4.0.2" + checksum: 10/ce617b8da36797d09c0baacb96ca8a44460452c89362d7cb8f70ca46b4158ba8bc3606912de7c818eb4a939f7f9015cef3c766ec8a0c6bfc725fdc078e39c717 + languageName: node + linkType: hard + "pirates@npm:^4.0.4": - version: 4.0.6 - resolution: "pirates@npm:4.0.6" - checksum: 10/d02dda76f4fec1cbdf395c36c11cf26f76a644f9f9a1bfa84d3167d0d3154d5289aacc72677aa20d599bb4a6937a471de1b65c995e2aea2d8687cbcd7e43ea5f + version: 4.0.7 + resolution: "pirates@npm:4.0.7" + checksum: 10/2427f371366081ae42feb58214f04805d6b41d6b84d74480ebcc9e0ddbd7105a139f7c653daeaf83ad8a1a77214cf07f64178e76de048128fec501eab3305a96 languageName: node linkType: hard @@ -3612,13 +3277,6 @@ __metadata: languageName: node linkType: hard -"prelude-ls@npm:^1.2.1": - version: 1.2.1 - resolution: "prelude-ls@npm:1.2.1" - checksum: 10/0b9d2c76801ca652a7f64892dd37b7e3fab149a37d2424920099bf894acccc62abb4424af2155ab36dea8744843060a2d8ddc983518d0b1e22265a22324b72ed - languageName: node - linkType: hard - "pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": version: 29.7.0 resolution: "pretty-format@npm:29.7.0" @@ -3657,13 +3315,6 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0": - version: 2.3.1 - resolution: "punycode@npm:2.3.1" - checksum: 10/febdc4362bead22f9e2608ff0171713230b57aff9dddc1c273aa2a651fbd366f94b7d6a71d78342a7c0819906750351ca7f2edd26ea41b626d87d6a13d1bd059 - languageName: node - linkType: hard - "pure-rand@npm:^6.0.0, pure-rand@npm:^6.1.0": version: 6.1.0 resolution: "pure-rand@npm:6.1.0" @@ -3671,13 +3322,6 @@ __metadata: languageName: node linkType: hard -"queue-microtask@npm:^1.2.2": - version: 1.2.3 - resolution: "queue-microtask@npm:1.2.3" - checksum: 10/72900df0616e473e824202113c3df6abae59150dfb73ed13273503127235320e9c8ca4aaaaccfd58cf417c6ca92a6e68ee9a5c3182886ae949a768639b388a7b - languageName: node - linkType: hard - "react-is@npm:^18.0.0": version: 18.3.1 resolution: "react-is@npm:18.3.1" @@ -3701,13 +3345,6 @@ __metadata: languageName: node linkType: hard -"resolve-from@npm:^4.0.0": - version: 4.0.0 - resolution: "resolve-from@npm:4.0.0" - checksum: 10/91eb76ce83621eea7bbdd9b55121a5c1c4a39e54a9ce04a9ad4517f102f8b5131c2cf07622c738a6683991bf54f2ce178f5a42803ecbd527ddc5105f362cc9e3 - languageName: node - linkType: hard - "resolve-from@npm:^5.0.0": version: 5.0.0 resolution: "resolve-from@npm:5.0.0" @@ -3748,39 +3385,20 @@ __metadata: languageName: node linkType: hard -"retry@npm:^0.12.0": - version: 0.12.0 - resolution: "retry@npm:0.12.0" - checksum: 10/1f914879f97e7ee931ad05fe3afa629bd55270fc6cf1c1e589b6a99fab96d15daad0fa1a52a00c729ec0078045fe3e399bd4fd0c93bcc906957bdc17f89cb8e6 - languageName: node - linkType: hard - -"reusify@npm:^1.0.4": - version: 1.1.0 - resolution: "reusify@npm:1.1.0" - checksum: 10/af47851b547e8a8dc89af144fceee17b80d5beaf5e6f57ed086432d79943434ff67ca526e92275be6f54b6189f6920a24eace75c2657eed32d02c400312b21ec - languageName: node - linkType: hard - -"rimraf@npm:^3.0.2": - version: 3.0.2 - resolution: "rimraf@npm:3.0.2" +"restore-cursor@npm:^5.0.0": + version: 5.1.0 + resolution: "restore-cursor@npm:5.1.0" dependencies: - glob: "npm:^7.1.3" - bin: - rimraf: bin.js - checksum: 10/063ffaccaaaca2cfd0ef3beafb12d6a03dd7ff1260d752d62a6077b5dfff6ae81bea571f655bb6b589d366930ec1bdd285d40d560c0dae9b12f125e54eb743d5 + onetime: "npm:^7.0.0" + signal-exit: "npm:^4.1.0" + checksum: 10/838dd54e458d89cfbc1a923b343c1b0f170a04100b4ce1733e97531842d7b440463967e521216e8ab6c6f8e89df877acc7b7f4c18ec76e99fb9bf5a60d358d2c languageName: node linkType: hard -"rimraf@npm:^5.0.5": - version: 5.0.10 - resolution: "rimraf@npm:5.0.10" - dependencies: - glob: "npm:^10.3.7" - bin: - rimraf: dist/esm/bin.mjs - checksum: 10/f3b8ce81eecbde4628b07bdf9e2fa8b684e0caea4999acb1e3b0402c695cd41f28cd075609a808e61ce2672f528ca079f675ab1d8e8d5f86d56643a03e0b8d2e +"retry@npm:^0.12.0": + version: 0.12.0 + resolution: "retry@npm:0.12.0" + checksum: 10/1f914879f97e7ee931ad05fe3afa629bd55270fc6cf1c1e589b6a99fab96d15daad0fa1a52a00c729ec0078045fe3e399bd4fd0c93bcc906957bdc17f89cb8e6 languageName: node linkType: hard @@ -3804,15 +3422,6 @@ __metadata: languageName: unknown linkType: soft -"run-parallel@npm:^1.1.9": - version: 1.2.0 - resolution: "run-parallel@npm:1.2.0" - dependencies: - queue-microtask: "npm:^1.2.2" - checksum: 10/cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d - languageName: node - linkType: hard - "safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" @@ -3861,7 +3470,7 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^4.0.1": +"signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" checksum: 10/c9fa63bbbd7431066174a48ba2dd9986dfd930c3a8b59de9c29d7b6854ec1c12a80d15310869ea5166d413b99f041bfa3dd80a7947bcd44ea8e6eb3ffeabfa1f @@ -3959,6 +3568,13 @@ __metadata: languageName: node linkType: hard +"stdin-discarder@npm:^0.2.2": + version: 0.2.2 + resolution: "stdin-discarder@npm:0.2.2" + checksum: 10/642ffd05bd5b100819d6b24a613d83c6e3857c6de74eb02fc51506fa61dc1b0034665163831873868157c4538d71e31762bcf319be86cea04c3aba5336470478 + languageName: node + linkType: hard + "string-length@npm:^4.0.1": version: 4.0.2 resolution: "string-length@npm:4.0.2" @@ -3991,6 +3607,17 @@ __metadata: languageName: node linkType: hard +"string-width@npm:^7.2.0": + version: 7.2.0 + resolution: "string-width@npm:7.2.0" + dependencies: + emoji-regex: "npm:^10.3.0" + get-east-asian-width: "npm:^1.0.0" + strip-ansi: "npm:^7.1.0" + checksum: 10/42f9e82f61314904a81393f6ef75b832c39f39761797250de68c041d8ba4df2ef80db49ab6cd3a292923a6f0f409b8c9980d120f7d32c820b4a8a84a2598a295 + languageName: node + linkType: hard + "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -4000,7 +3627,7 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^7.0.1": +"strip-ansi@npm:^7.0.1, strip-ansi@npm:^7.1.0": version: 7.1.0 resolution: "strip-ansi@npm:7.1.0" dependencies: @@ -4080,10 +3707,13 @@ __metadata: languageName: node linkType: hard -"text-table@npm:^0.2.0": - version: 0.2.0 - resolution: "text-table@npm:0.2.0" - checksum: 10/4383b5baaeffa9bb4cda2ac33a4aa2e6d1f8aaf811848bf73513a9b88fd76372dc461f6fd6d2e9cb5100f48b473be32c6f95bd983509b7d92bb4d92c10747452 +"tinyglobby@npm:^0.2.12": + version: 0.2.13 + resolution: "tinyglobby@npm:0.2.13" + dependencies: + fdir: "npm:^6.4.4" + picomatch: "npm:^4.0.2" + checksum: 10/b04557ee58ad2be5f2d2cbb4b441476436c92bb45ba2e1fc464d686b793392b305ed0bcb8b877429e9b5036bdd46770c161a08384c0720b6682b7cd6ac80e403 languageName: node linkType: hard @@ -4104,8 +3734,8 @@ __metadata: linkType: hard "ts-jest@npm:^29.1.1": - version: 29.2.6 - resolution: "ts-jest@npm:29.2.6" + version: 29.3.2 + resolution: "ts-jest@npm:29.3.2" dependencies: bs-logger: "npm:^0.2.6" ejs: "npm:^3.1.10" @@ -4115,6 +3745,7 @@ __metadata: lodash.memoize: "npm:^4.1.2" make-error: "npm:^1.3.6" semver: "npm:^7.7.1" + type-fest: "npm:^4.39.1" yargs-parser: "npm:^21.1.1" peerDependencies: "@babel/core": ">=7.0.0-beta.0 <8" @@ -4136,11 +3767,11 @@ __metadata: optional: true bin: ts-jest: cli.js - checksum: 10/9cb6804266be7c9384cecace346f65d2ab5a685d252c5275b53b5958f6545951328a5c4d48c49c5f92d1e04187ca31e348e5a3540d20cb365c33d1eb89371e22 + checksum: 10/62fb226a4df408174a3f28919c89440b2f5df4dec404bb49696591e61d75536b1c3be8ae726d187958a467654d82294d81d2dd70d9ec370542a30907183aaf61 languageName: node linkType: hard -"ts-node@npm:^10.9.1, ts-node@npm:^10.9.2": +"ts-node@npm:^10.9.1": version: 10.9.2 resolution: "ts-node@npm:10.9.2" dependencies: @@ -4178,58 +3809,58 @@ __metadata: languageName: node linkType: hard -"turbo-darwin-64@npm:2.5.1": - version: 2.5.1 - resolution: "turbo-darwin-64@npm:2.5.1" +"turbo-darwin-64@npm:2.5.2": + version: 2.5.2 + resolution: "turbo-darwin-64@npm:2.5.2" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"turbo-darwin-arm64@npm:2.5.1": - version: 2.5.1 - resolution: "turbo-darwin-arm64@npm:2.5.1" +"turbo-darwin-arm64@npm:2.5.2": + version: 2.5.2 + resolution: "turbo-darwin-arm64@npm:2.5.2" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"turbo-linux-64@npm:2.5.1": - version: 2.5.1 - resolution: "turbo-linux-64@npm:2.5.1" +"turbo-linux-64@npm:2.5.2": + version: 2.5.2 + resolution: "turbo-linux-64@npm:2.5.2" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"turbo-linux-arm64@npm:2.5.1": - version: 2.5.1 - resolution: "turbo-linux-arm64@npm:2.5.1" +"turbo-linux-arm64@npm:2.5.2": + version: 2.5.2 + resolution: "turbo-linux-arm64@npm:2.5.2" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"turbo-windows-64@npm:2.5.1": - version: 2.5.1 - resolution: "turbo-windows-64@npm:2.5.1" +"turbo-windows-64@npm:2.5.2": + version: 2.5.2 + resolution: "turbo-windows-64@npm:2.5.2" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"turbo-windows-arm64@npm:2.5.1": - version: 2.5.1 - resolution: "turbo-windows-arm64@npm:2.5.1" +"turbo-windows-arm64@npm:2.5.2": + version: 2.5.2 + resolution: "turbo-windows-arm64@npm:2.5.2" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard "turbo@npm:^2.5.1": - version: 2.5.1 - resolution: "turbo@npm:2.5.1" - dependencies: - turbo-darwin-64: "npm:2.5.1" - turbo-darwin-arm64: "npm:2.5.1" - turbo-linux-64: "npm:2.5.1" - turbo-linux-arm64: "npm:2.5.1" - turbo-windows-64: "npm:2.5.1" - turbo-windows-arm64: "npm:2.5.1" + version: 2.5.2 + resolution: "turbo@npm:2.5.2" + dependencies: + turbo-darwin-64: "npm:2.5.2" + turbo-darwin-arm64: "npm:2.5.2" + turbo-linux-64: "npm:2.5.2" + turbo-linux-arm64: "npm:2.5.2" + turbo-windows-64: "npm:2.5.2" + turbo-windows-arm64: "npm:2.5.2" dependenciesMeta: turbo-darwin-64: optional: true @@ -4245,16 +3876,7 @@ __metadata: optional: true bin: turbo: bin/turbo - checksum: 10/54d7c16d7cc9b60098db62d37940bef4663a14344bada1cb521e3260b6c30ec4bebc88a3dbb4108e4a3436fdc32b43091323f9d841ad3198719513765a73ddd9 - languageName: node - linkType: hard - -"type-check@npm:^0.4.0, type-check@npm:~0.4.0": - version: 0.4.0 - resolution: "type-check@npm:0.4.0" - dependencies: - prelude-ls: "npm:^1.2.1" - checksum: 10/14687776479d048e3c1dbfe58a2409e00367810d6960c0f619b33793271ff2a27f81b52461f14a162f1f89a9b1d8da1b237fc7c99b0e1fdcec28ec63a86b1fec + checksum: 10/dee9047dbeeddd5584744e604620267749e278e71f9658fd58ca72f6f71d38c47132ea958aee7b7049e51c85bcfce35ca6efb1e8d180b03d7504d7427f05b026 languageName: node linkType: hard @@ -4265,13 +3887,6 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^0.20.2": - version: 0.20.2 - resolution: "type-fest@npm:0.20.2" - checksum: 10/8907e16284b2d6cfa4f4817e93520121941baba36b39219ea36acfe64c86b9dbc10c9941af450bd60832c8f43464974d51c0957f9858bc66b952b66b6914cbb9 - languageName: node - linkType: hard - "type-fest@npm:^0.21.3": version: 0.21.3 resolution: "type-fest@npm:0.21.3" @@ -4279,23 +3894,30 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.2.2": - version: 5.8.2 - resolution: "typescript@npm:5.8.2" +"type-fest@npm:^4.39.1": + version: 4.40.1 + resolution: "type-fest@npm:4.40.1" + checksum: 10/907767cd7889c8f17d94f4a811ec27c33339a9134f6842a1a56b4d6ee87cb1d6b01332f366a3f03adc10923fd6d511d73b73076f7ab5256bf5c0b43a03ab6e8b + languageName: node + linkType: hard + +"typescript@npm:^5.2.2, typescript@npm:^5.8.2": + version: 5.8.3 + resolution: "typescript@npm:5.8.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10/dbc2168a55d56771f4d581997be52bab5cbc09734fec976cfbaabd787e61fb4c6cf9125fd48c6f98054ce549c77ecedefc7f64252a830dd8e9c3381f61fbeb78 + checksum: 10/65c40944c51b513b0172c6710ee62e951b70af6f75d5a5da745cb7fab132c09ae27ffdf7838996e3ed603bb015dadd099006658046941bd0ba30340cc563ae92 languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.2.2#optional!builtin": - version: 5.8.2 - resolution: "typescript@patch:typescript@npm%3A5.8.2#optional!builtin::version=5.8.2&hash=d69c25" +"typescript@patch:typescript@npm%3A^5.2.2#optional!builtin, typescript@patch:typescript@npm%3A^5.8.2#optional!builtin": + version: 5.8.3 + resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin::version=5.8.3&hash=d69c25" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10/6ae9b2c4d3254ec2eaee6f26ed997e19c02177a212422993209f81e87092b2bb0a4738085549c5b0164982a5609364c047c72aeb281f6c8d802cd0d1c6f0d353 + checksum: 10/98470634034ec37fd9ea61cc82dcf9a27950d0117a4646146b767d085a2ec14b137aae9642a83d1c62732d7fdcdac19bb6288b0bb468a72f7a06ae4e1d2c72c9 languageName: node linkType: hard @@ -4306,10 +3928,10 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~6.20.0": - version: 6.20.0 - resolution: "undici-types@npm:6.20.0" - checksum: 10/583ac7bbf4ff69931d3985f4762cde2690bb607844c16a5e2fbb92ed312fe4fa1b365e953032d469fa28ba8b224e88a595f0b10a449332f83fa77c695e567dbe +"undici-types@npm:~6.21.0": + version: 6.21.0 + resolution: "undici-types@npm:6.21.0" + checksum: 10/ec8f41aa4359d50f9b59fa61fe3efce3477cc681908c8f84354d8567bb3701fafdddf36ef6bff307024d3feb42c837cf6f670314ba37fc8145e219560e473d14 languageName: node linkType: hard @@ -4345,15 +3967,6 @@ __metadata: languageName: node linkType: hard -"uri-js@npm:^4.2.2": - version: 4.4.1 - resolution: "uri-js@npm:4.4.1" - dependencies: - punycode: "npm:^2.1.0" - checksum: 10/b271ca7e3d46b7160222e3afa3e531505161c9a4e097febae9664e4b59912f4cbe94861361a4175edac3a03fee99d91e44b6a58c17a634bc5a664b19fc76fbcb - languageName: node - linkType: hard - "v8-compile-cache-lib@npm:^3.0.1": version: 3.0.1 resolution: "v8-compile-cache-lib@npm:3.0.1" @@ -4403,13 +4016,6 @@ __metadata: languageName: node linkType: hard -"word-wrap@npm:^1.2.5": - version: 1.2.5 - resolution: "word-wrap@npm:1.2.5" - checksum: 10/1ec6f6089f205f83037be10d0c4b34c9183b0b63fca0834a5b3cee55dd321429d73d40bb44c8fc8471b5203d6e8f8275717f49a8ff4b2b0ab41d7e1b563e0854 - languageName: node - linkType: hard - "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" @@ -4512,3 +4118,10 @@ __metadata: checksum: 10/f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 languageName: node linkType: hard + +"yoctocolors@npm:^2.1.1": + version: 2.1.1 + resolution: "yoctocolors@npm:2.1.1" + checksum: 10/563fbec88bce9716d1044bc98c96c329e1d7a7c503e6f1af68f1ff914adc3ba55ce953c871395e2efecad329f85f1632f51a99c362032940321ff80c42a6f74d + languageName: node + linkType: hard From c4d70315b36564aaa1ee095ecfb677032a3df943 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 16 May 2025 16:04:44 -0500 Subject: [PATCH 077/282] migrate to vitest, bump compact-runtime --- compact/package.json | 9 +- contracts/utils/package.json | 7 +- contracts/utils/src/Initializable.compact | 2 +- contracts/utils/src/Pausable.compact | 2 +- contracts/utils/src/Utils.compact | 2 +- .../utils/src/test/Initializable.test.ts | 2 +- contracts/utils/src/test/Pausable.test.ts | 2 +- .../src/test/mocks/MockInitializable.compact | 2 +- .../utils/src/test/mocks/MockPausable.compact | 2 +- .../utils/src/test/mocks/MockUtils.compact | 4 +- contracts/utils/src/test/utils.test.ts | 1 + contracts/utils/vitest.config.ts | 9 + package.json | 16 +- yarn.lock | 3643 +++++------------ 14 files changed, 1013 insertions(+), 2690 deletions(-) create mode 100644 contracts/utils/vitest.config.ts diff --git a/compact/package.json b/compact/package.json index 7e811f4f..8ee95ee9 100644 --- a/compact/package.json +++ b/compact/package.json @@ -2,7 +2,10 @@ "packageManager": "yarn@4.1.0", "name": "@openzeppelin-midnight/compact", "version": "0.0.1", - "keywords": ["compact", "compiler"], + "keywords": [ + "compact", + "compiler" + ], "author": "", "license": "MIT", "description": "Compact fetcher", @@ -24,12 +27,8 @@ "clean": "git clean -fXd" }, "devDependencies": { - "@types/jest": "^29.5.6", "@types/node": "^22.13.10", "fast-check": "^3.15.0", - "jest": "^29.7.0", - "jest-fast-check": "^2.0.0", - "ts-jest": "^29.1.1", "typescript": "^5.8.2" }, "dependencies": { diff --git a/contracts/utils/package.json b/contracts/utils/package.json index f8333f63..4f0ee469 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -15,7 +15,7 @@ "scripts": { "compact": "npx compact-compiler", "build": "npx compact-builder && tsc", - "test": "NODE_OPTIONS=--experimental-vm-modules jest", + "test": "vitest", "types": "tsc -p tsconfig.json --noEmit", "fmt": "biome format", "fmt:fix": "biome format --write", @@ -30,6 +30,9 @@ "@openzeppelin-midnight/compact": "workspace:^", "@biomejs/biome": "1.9.4", "@types/node": "^18.18.6", - "typescript": "^5.2.2" + "@vitest/ui": "^3.1.3", + "ts-node": "^10.9.2", + "typescript": "^5.2.2", + "vitest": "^3.1.3" } } diff --git a/contracts/utils/src/Initializable.compact b/contracts/utils/src/Initializable.compact index a31c9bcf..99a2c0e1 100644 --- a/contracts/utils/src/Initializable.compact +++ b/contracts/utils/src/Initializable.compact @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma language_version >= 0.14.0; +pragma language_version >= 0.15.0; /** * @module Initializable diff --git a/contracts/utils/src/Pausable.compact b/contracts/utils/src/Pausable.compact index 8e9eba5b..11e0ba04 100644 --- a/contracts/utils/src/Pausable.compact +++ b/contracts/utils/src/Pausable.compact @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma language_version >= 0.14.0; +pragma language_version >= 0.15.0; /** * @module Pausable diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index a14bd91a..686a644f 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma language_version >= 0.14.0; +pragma language_version >= 0.15.0; /** * @module Utils. diff --git a/contracts/utils/src/test/Initializable.test.ts b/contracts/utils/src/test/Initializable.test.ts index fdb8783b..21a81929 100644 --- a/contracts/utils/src/test/Initializable.test.ts +++ b/contracts/utils/src/test/Initializable.test.ts @@ -1,5 +1,5 @@ -import { describe, expect, it } from '@jest/globals'; import { InitializableSimulator } from './simulators/InitializableSimulator'; +import { expect } from 'vitest' let initializable: InitializableSimulator; diff --git a/contracts/utils/src/test/Pausable.test.ts b/contracts/utils/src/test/Pausable.test.ts index d969b431..1098e7af 100644 --- a/contracts/utils/src/test/Pausable.test.ts +++ b/contracts/utils/src/test/Pausable.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it } from '@jest/globals'; +import { expect } from 'vitest' import { PausableSimulator } from './simulators/PausableSimulator'; let pausable: PausableSimulator; diff --git a/contracts/utils/src/test/mocks/MockInitializable.compact b/contracts/utils/src/test/mocks/MockInitializable.compact index e8722a47..99a07dc8 100644 --- a/contracts/utils/src/test/mocks/MockInitializable.compact +++ b/contracts/utils/src/test/mocks/MockInitializable.compact @@ -1,4 +1,4 @@ -pragma language_version >= 0.14.0; +pragma language_version >= 0.15.0; import CompactStandardLibrary; import "../../Initializable" prefix Initializable_; diff --git a/contracts/utils/src/test/mocks/MockPausable.compact b/contracts/utils/src/test/mocks/MockPausable.compact index a564fbe6..17e26bb6 100644 --- a/contracts/utils/src/test/mocks/MockPausable.compact +++ b/contracts/utils/src/test/mocks/MockPausable.compact @@ -1,4 +1,4 @@ -pragma language_version >= 0.14.0; +pragma language_version >= 0.15.0; import CompactStandardLibrary; import "../../Pausable" prefix Pausable_; diff --git a/contracts/utils/src/test/mocks/MockUtils.compact b/contracts/utils/src/test/mocks/MockUtils.compact index 2044da04..152e74a1 100644 --- a/contracts/utils/src/test/mocks/MockUtils.compact +++ b/contracts/utils/src/test/mocks/MockUtils.compact @@ -1,6 +1,4 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.14.0; +pragma language_version >= 0.15.0; import CompactStandardLibrary; diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 40360a45..42ac1a27 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -1,5 +1,6 @@ import { UtilsSimulator } from './simulators/UtilsSimulator'; import * as contractUtils from './utils/address'; +import { expect } from 'vitest' const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); diff --git a/contracts/utils/vitest.config.ts b/contracts/utils/vitest.config.ts new file mode 100644 index 00000000..72f7fab7 --- /dev/null +++ b/contracts/utils/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['src/test/**/*.test.ts'], + }, +}); diff --git a/package.json b/package.json index eef2ac9b..e1c31350 100644 --- a/package.json +++ b/package.json @@ -17,20 +17,18 @@ "clean": "turbo run clean" }, "dependencies": { - "@midnight-ntwrk/compact-runtime": "^0.7.0" + "@midnight-ntwrk/compact-runtime": "^0.8.0" }, "devDependencies": { "@biomejs/biome": "1.9.4", - "@midnight-ntwrk/ledger": "^3.0.6", - "@midnight-ntwrk/zswap": "^3.0.6", - "@types/jest": "^29.5.6", + "@midnight-ntwrk/ledger": "^4.0.0", + "@midnight-ntwrk/zswap": "^4.0.0", "@types/node": "^18.18.6", + "@vitest/ui": "^3.1.3", "fast-check": "^3.15.0", - "jest": "^29.7.0", - "jest-fast-check": "^2.0.0", - "ts-jest": "^29.1.1", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "turbo": "^2.5.1", - "typescript": "^5.2.2" + "typescript": "^5.2.2", + "vitest": "^3.1.3" } } diff --git a/yarn.lock b/yarn.lock index 0bb1b54d..c8976613 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,385 +5,6 @@ __metadata: version: 8 cacheKey: 10 -"@ampproject/remapping@npm:^2.2.0": - version: 2.3.0 - resolution: "@ampproject/remapping@npm:2.3.0" - dependencies: - "@jridgewell/gen-mapping": "npm:^0.3.5" - "@jridgewell/trace-mapping": "npm:^0.3.24" - checksum: 10/f3451525379c68a73eb0a1e65247fbf28c0cccd126d93af21c75fceff77773d43c0d4a2d51978fb131aff25b5f2cb41a9fe48cc296e61ae65e679c4f6918b0ab - languageName: node - linkType: hard - -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.26.2": - version: 7.26.2 - resolution: "@babel/code-frame@npm:7.26.2" - dependencies: - "@babel/helper-validator-identifier": "npm:^7.25.9" - js-tokens: "npm:^4.0.0" - picocolors: "npm:^1.0.0" - checksum: 10/db2c2122af79d31ca916755331bb4bac96feb2b334cdaca5097a6b467fdd41963b89b14b6836a14f083de7ff887fc78fa1b3c10b14e743d33e12dbfe5ee3d223 - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.26.8": - version: 7.26.8 - resolution: "@babel/compat-data@npm:7.26.8" - checksum: 10/bdddf577f670e0e12996ef37e134856c8061032edb71a13418c3d4dae8135da28910b7cd6dec6e668ab3a41e42089ef7ee9c54ef52fe0860b54cb420b0d14948 - languageName: node - linkType: hard - -"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.23.9": - version: 7.26.10 - resolution: "@babel/core@npm:7.26.10" - dependencies: - "@ampproject/remapping": "npm:^2.2.0" - "@babel/code-frame": "npm:^7.26.2" - "@babel/generator": "npm:^7.26.10" - "@babel/helper-compilation-targets": "npm:^7.26.5" - "@babel/helper-module-transforms": "npm:^7.26.0" - "@babel/helpers": "npm:^7.26.10" - "@babel/parser": "npm:^7.26.10" - "@babel/template": "npm:^7.26.9" - "@babel/traverse": "npm:^7.26.10" - "@babel/types": "npm:^7.26.10" - convert-source-map: "npm:^2.0.0" - debug: "npm:^4.1.0" - gensync: "npm:^1.0.0-beta.2" - json5: "npm:^2.2.3" - semver: "npm:^6.3.1" - checksum: 10/68f6707eebd6bb8beed7ceccf5153e35b86c323e40d11d796d75c626ac8f1cc4e1f795584c5ab5f886bc64150c22d5088123d68c069c63f29984c4fc054d1dab - languageName: node - linkType: hard - -"@babel/generator@npm:^7.26.10, @babel/generator@npm:^7.27.0, @babel/generator@npm:^7.7.2": - version: 7.27.0 - resolution: "@babel/generator@npm:7.27.0" - dependencies: - "@babel/parser": "npm:^7.27.0" - "@babel/types": "npm:^7.27.0" - "@jridgewell/gen-mapping": "npm:^0.3.5" - "@jridgewell/trace-mapping": "npm:^0.3.25" - jsesc: "npm:^3.0.2" - checksum: 10/5447c402b1d841132534a0a9715e89f4f28b6f2886a23e70aaa442150dba4a1e29e4e2351814f439ee1775294dccdef9ab0a4192b6e6a5ad44e24233b3611da2 - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.26.5": - version: 7.27.0 - resolution: "@babel/helper-compilation-targets@npm:7.27.0" - dependencies: - "@babel/compat-data": "npm:^7.26.8" - "@babel/helper-validator-option": "npm:^7.25.9" - browserslist: "npm:^4.24.0" - lru-cache: "npm:^5.1.1" - semver: "npm:^6.3.1" - checksum: 10/32224b512e813fc808539b4ca7fca8c224849487c365abcef8cb8b0eea635c65375b81429f82d076e9ec1f3f3b3db1d0d56aac4d482a413f58d5ad608f912155 - languageName: node - linkType: hard - -"@babel/helper-module-imports@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-module-imports@npm:7.25.9" - dependencies: - "@babel/traverse": "npm:^7.25.9" - "@babel/types": "npm:^7.25.9" - checksum: 10/e090be5dee94dda6cd769972231b21ddfae988acd76b703a480ac0c96f3334557d70a965bf41245d6ee43891e7571a8b400ccf2b2be5803351375d0f4e5bcf08 - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.26.0": - version: 7.26.0 - resolution: "@babel/helper-module-transforms@npm:7.26.0" - dependencies: - "@babel/helper-module-imports": "npm:^7.25.9" - "@babel/helper-validator-identifier": "npm:^7.25.9" - "@babel/traverse": "npm:^7.25.9" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/9841d2a62f61ad52b66a72d08264f23052d533afc4ce07aec2a6202adac0bfe43014c312f94feacb3291f4c5aafe681955610041ece2c276271adce3f570f2f5 - languageName: node - linkType: hard - -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.25.9, @babel/helper-plugin-utils@npm:^7.8.0": - version: 7.26.5 - resolution: "@babel/helper-plugin-utils@npm:7.26.5" - checksum: 10/1cc0fd8514da3bb249bed6c27227696ab5e84289749d7258098701cffc0c599b7f61ec40dd332f8613030564b79899d9826813c96f966330bcfc7145a8377857 - languageName: node - linkType: hard - -"@babel/helper-string-parser@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-string-parser@npm:7.25.9" - checksum: 10/c28656c52bd48e8c1d9f3e8e68ecafd09d949c57755b0d353739eb4eae7ba4f7e67e92e4036f1cd43378cc1397a2c943ed7bcaf5949b04ab48607def0258b775 - languageName: node - linkType: hard - -"@babel/helper-validator-identifier@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-validator-identifier@npm:7.25.9" - checksum: 10/3f9b649be0c2fd457fa1957b694b4e69532a668866b8a0d81eabfa34ba16dbf3107b39e0e7144c55c3c652bf773ec816af8df4a61273a2bb4eb3145ca9cf478e - languageName: node - linkType: hard - -"@babel/helper-validator-option@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-validator-option@npm:7.25.9" - checksum: 10/9491b2755948ebbdd68f87da907283698e663b5af2d2b1b02a2765761974b1120d5d8d49e9175b167f16f72748ffceec8c9cf62acfbee73f4904507b246e2b3d - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.26.10": - version: 7.27.0 - resolution: "@babel/helpers@npm:7.27.0" - dependencies: - "@babel/template": "npm:^7.27.0" - "@babel/types": "npm:^7.27.0" - checksum: 10/0dd40ba1e5ba4b72d1763bb381384585a56f21a61a19dc1b9a03381fe8e840207fdaa4da645d14dc028ad768087d41aad46347cc6573bd69d82f597f5a12dc6f - languageName: node - linkType: hard - -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.26.10, @babel/parser@npm:^7.27.0": - version: 7.27.0 - resolution: "@babel/parser@npm:7.27.0" - dependencies: - "@babel/types": "npm:^7.27.0" - bin: - parser: ./bin/babel-parser.js - checksum: 10/0fee9f05c6db753882ca9d10958301493443da9f6986d7020ebd7a696b35886240016899bc0b47d871aea2abcafd64632343719742e87432c8145e0ec2af2a03 - languageName: node - linkType: hard - -"@babel/plugin-syntax-async-generators@npm:^7.8.4": - version: 7.8.4 - resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/7ed1c1d9b9e5b64ef028ea5e755c0be2d4e5e4e3d6cf7df757b9a8c4cfa4193d268176d0f1f7fbecdda6fe722885c7fda681f480f3741d8a2d26854736f05367 - languageName: node - linkType: hard - -"@babel/plugin-syntax-bigint@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-bigint@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/3a10849d83e47aec50f367a9e56a6b22d662ddce643334b087f9828f4c3dd73bdc5909aaeabe123fed78515767f9ca43498a0e621c438d1cd2802d7fae3c9648 - languageName: node - linkType: hard - -"@babel/plugin-syntax-class-properties@npm:^7.12.13": - version: 7.12.13 - resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.12.13" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/24f34b196d6342f28d4bad303612d7ff566ab0a013ce89e775d98d6f832969462e7235f3e7eaf17678a533d4be0ba45d3ae34ab4e5a9dcbda5d98d49e5efa2fc - languageName: node - linkType: hard - -"@babel/plugin-syntax-class-static-block@npm:^7.14.5": - version: 7.14.5 - resolution: "@babel/plugin-syntax-class-static-block@npm:7.14.5" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.14.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/3e80814b5b6d4fe17826093918680a351c2d34398a914ce6e55d8083d72a9bdde4fbaf6a2dcea0e23a03de26dc2917ae3efd603d27099e2b98380345703bf948 - languageName: node - linkType: hard - -"@babel/plugin-syntax-import-attributes@npm:^7.24.7": - version: 7.26.0 - resolution: "@babel/plugin-syntax-import-attributes@npm:7.26.0" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/c122aa577166c80ee67f75aebebeef4150a132c4d3109d25d7fc058bf802946f883e330f20b78c1d3e3a5ada631c8780c263d2d01b5dbaecc69efefeedd42916 - languageName: node - linkType: hard - -"@babel/plugin-syntax-import-meta@npm:^7.10.4": - version: 7.10.4 - resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.10.4" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/166ac1125d10b9c0c430e4156249a13858c0366d38844883d75d27389621ebe651115cb2ceb6dc011534d5055719fa1727b59f39e1ab3ca97820eef3dcab5b9b - languageName: node - linkType: hard - -"@babel/plugin-syntax-json-strings@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-json-strings@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/bf5aea1f3188c9a507e16efe030efb996853ca3cadd6512c51db7233cc58f3ac89ff8c6bdfb01d30843b161cfe7d321e1bf28da82f7ab8d7e6bc5464666f354a - languageName: node - linkType: hard - -"@babel/plugin-syntax-jsx@npm:^7.7.2": - version: 7.25.9 - resolution: "@babel/plugin-syntax-jsx@npm:7.25.9" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/bb609d1ffb50b58f0c1bac8810d0e46a4f6c922aa171c458f3a19d66ee545d36e782d3bffbbc1fed0dc65a558bdce1caf5279316583c0fff5a2c1658982a8563 - languageName: node - linkType: hard - -"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4": - version: 7.10.4 - resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.10.4" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/aff33577037e34e515911255cdbb1fd39efee33658aa00b8a5fd3a4b903585112d037cce1cc9e4632f0487dc554486106b79ccd5ea63a2e00df4363f6d4ff886 - languageName: node - linkType: hard - -"@babel/plugin-syntax-nullish-coalescing-operator@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-nullish-coalescing-operator@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/87aca4918916020d1fedba54c0e232de408df2644a425d153be368313fdde40d96088feed6c4e5ab72aac89be5d07fef2ddf329a15109c5eb65df006bf2580d1 - languageName: node - linkType: hard - -"@babel/plugin-syntax-numeric-separator@npm:^7.10.4": - version: 7.10.4 - resolution: "@babel/plugin-syntax-numeric-separator@npm:7.10.4" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.10.4" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/01ec5547bd0497f76cc903ff4d6b02abc8c05f301c88d2622b6d834e33a5651aa7c7a3d80d8d57656a4588f7276eba357f6b7e006482f5b564b7a6488de493a1 - languageName: node - linkType: hard - -"@babel/plugin-syntax-object-rest-spread@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-object-rest-spread@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/fddcf581a57f77e80eb6b981b10658421bc321ba5f0a5b754118c6a92a5448f12a0c336f77b8abf734841e102e5126d69110a306eadb03ca3e1547cab31f5cbf - languageName: node - linkType: hard - -"@babel/plugin-syntax-optional-catch-binding@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-optional-catch-binding@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/910d90e72bc90ea1ce698e89c1027fed8845212d5ab588e35ef91f13b93143845f94e2539d831dc8d8ededc14ec02f04f7bd6a8179edd43a326c784e7ed7f0b9 - languageName: node - linkType: hard - -"@babel/plugin-syntax-optional-chaining@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-optional-chaining@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/eef94d53a1453361553c1f98b68d17782861a04a392840341bc91780838dd4e695209c783631cf0de14c635758beafb6a3a65399846ffa4386bff90639347f30 - languageName: node - linkType: hard - -"@babel/plugin-syntax-private-property-in-object@npm:^7.14.5": - version: 7.14.5 - resolution: "@babel/plugin-syntax-private-property-in-object@npm:7.14.5" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.14.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/b317174783e6e96029b743ccff2a67d63d38756876e7e5d0ba53a322e38d9ca452c13354a57de1ad476b4c066dbae699e0ca157441da611117a47af88985ecda - languageName: node - linkType: hard - -"@babel/plugin-syntax-top-level-await@npm:^7.14.5": - version: 7.14.5 - resolution: "@babel/plugin-syntax-top-level-await@npm:7.14.5" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.14.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/bbd1a56b095be7820029b209677b194db9b1d26691fe999856462e66b25b281f031f3dfd91b1619e9dcf95bebe336211833b854d0fb8780d618e35667c2d0d7e - languageName: node - linkType: hard - -"@babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.25.9 - resolution: "@babel/plugin-syntax-typescript@npm:7.25.9" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/0e9821e8ba7d660c36c919654e4144a70546942ae184e85b8102f2322451eae102cbfadbcadd52ce077a2b44b400ee52394c616feab7b5b9f791b910e933fd33 - languageName: node - linkType: hard - -"@babel/template@npm:^7.26.9, @babel/template@npm:^7.27.0, @babel/template@npm:^7.3.3": - version: 7.27.0 - resolution: "@babel/template@npm:7.27.0" - dependencies: - "@babel/code-frame": "npm:^7.26.2" - "@babel/parser": "npm:^7.27.0" - "@babel/types": "npm:^7.27.0" - checksum: 10/7159ca1daea287ad34676d45a7146675444d42c7664aca3e617abc9b1d9548c8f377f35a36bb34cf956e1d3610dcb7acfcfe890aebf81880d35f91a7bd273ee5 - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.10": - version: 7.27.0 - resolution: "@babel/traverse@npm:7.27.0" - dependencies: - "@babel/code-frame": "npm:^7.26.2" - "@babel/generator": "npm:^7.27.0" - "@babel/parser": "npm:^7.27.0" - "@babel/template": "npm:^7.27.0" - "@babel/types": "npm:^7.27.0" - debug: "npm:^4.3.1" - globals: "npm:^11.1.0" - checksum: 10/b0675bc16bd87187e8b090557b0650135de56a621692ad8614b20f32621350ae0fc2e1129b73b780d64a9ed4beab46849a17f90d5267b6ae6ce09ec8412a12c7 - languageName: node - linkType: hard - -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.10, @babel/types@npm:^7.27.0, @babel/types@npm:^7.3.3": - version: 7.27.0 - resolution: "@babel/types@npm:7.27.0" - dependencies: - "@babel/helper-string-parser": "npm:^7.25.9" - "@babel/helper-validator-identifier": "npm:^7.25.9" - checksum: 10/2c322bce107c8a534dc4a23be60d570e6a4cc7ca2e44d4f0eee08c0b626104eb7e60ab8de03463bc5da1773a2f69f1e6edec1648d648d65461d6520a7f3b0770 - languageName: node - linkType: hard - -"@bcoe/v8-coverage@npm:^0.2.3": - version: 0.2.3 - resolution: "@bcoe/v8-coverage@npm:0.2.3" - checksum: 10/1a1f0e356a3bb30b5f1ced6f79c413e6ebacf130421f15fac5fcd8be5ddf98aedb4404d7f5624e3285b700e041f9ef938321f3ca4d359d5b716f96afa120d88d - languageName: node - linkType: hard - "@biomejs/biome@npm:1.9.4": version: 1.9.4 resolution: "@biomejs/biome@npm:1.9.4" @@ -484,305 +105,212 @@ __metadata: languageName: node linkType: hard -"@isaacs/cliui@npm:^8.0.2": - version: 8.0.2 - resolution: "@isaacs/cliui@npm:8.0.2" - dependencies: - string-width: "npm:^5.1.2" - string-width-cjs: "npm:string-width@^4.2.0" - strip-ansi: "npm:^7.0.1" - strip-ansi-cjs: "npm:strip-ansi@^6.0.1" - wrap-ansi: "npm:^8.1.0" - wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" - checksum: 10/e9ed5fd27c3aec1095e3a16e0c0cf148d1fee55a38665c35f7b3f86a9b5d00d042ddaabc98e8a1cb7463b9378c15f22a94eb35e99469c201453eb8375191f243 +"@esbuild/aix-ppc64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/aix-ppc64@npm:0.25.4" + conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@isaacs/fs-minipass@npm:^4.0.0": - version: 4.0.1 - resolution: "@isaacs/fs-minipass@npm:4.0.1" - dependencies: - minipass: "npm:^7.0.4" - checksum: 10/4412e9e6713c89c1e66d80bb0bb5a2a93192f10477623a27d08f228ba0316bb880affabc5bfe7f838f58a34d26c2c190da726e576cdfc18c49a72e89adabdcf5 +"@esbuild/android-arm64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/android-arm64@npm:0.25.4" + conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@istanbuljs/load-nyc-config@npm:^1.0.0": - version: 1.1.0 - resolution: "@istanbuljs/load-nyc-config@npm:1.1.0" - dependencies: - camelcase: "npm:^5.3.1" - find-up: "npm:^4.1.0" - get-package-type: "npm:^0.1.0" - js-yaml: "npm:^3.13.1" - resolve-from: "npm:^5.0.0" - checksum: 10/b000a5acd8d4fe6e34e25c399c8bdbb5d3a202b4e10416e17bfc25e12bab90bb56d33db6089ae30569b52686f4b35ff28ef26e88e21e69821d2b85884bd055b8 +"@esbuild/android-arm@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/android-arm@npm:0.25.4" + conditions: os=android & cpu=arm languageName: node linkType: hard -"@istanbuljs/schema@npm:^0.1.2, @istanbuljs/schema@npm:^0.1.3": - version: 0.1.3 - resolution: "@istanbuljs/schema@npm:0.1.3" - checksum: 10/a9b1e49acdf5efc2f5b2359f2df7f90c5c725f2656f16099e8b2cd3a000619ecca9fc48cf693ba789cf0fd989f6e0df6a22bc05574be4223ecdbb7997d04384b +"@esbuild/android-x64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/android-x64@npm:0.25.4" + conditions: os=android & cpu=x64 languageName: node linkType: hard -"@jest/console@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/console@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - chalk: "npm:^4.0.0" - jest-message-util: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - slash: "npm:^3.0.0" - checksum: 10/4a80c750e8a31f344233cb9951dee9b77bf6b89377cb131f8b3cde07ff218f504370133a5963f6a786af4d2ce7f85642db206ff7a15f99fe58df4c38ac04899e +"@esbuild/darwin-arm64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/darwin-arm64@npm:0.25.4" + conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@jest/core@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/core@npm:29.7.0" - dependencies: - "@jest/console": "npm:^29.7.0" - "@jest/reporters": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - ansi-escapes: "npm:^4.2.1" - chalk: "npm:^4.0.0" - ci-info: "npm:^3.2.0" - exit: "npm:^0.1.2" - graceful-fs: "npm:^4.2.9" - jest-changed-files: "npm:^29.7.0" - jest-config: "npm:^29.7.0" - jest-haste-map: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-regex-util: "npm:^29.6.3" - jest-resolve: "npm:^29.7.0" - jest-resolve-dependencies: "npm:^29.7.0" - jest-runner: "npm:^29.7.0" - jest-runtime: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - jest-watcher: "npm:^29.7.0" - micromatch: "npm:^4.0.4" - pretty-format: "npm:^29.7.0" - slash: "npm:^3.0.0" - strip-ansi: "npm:^6.0.0" - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - checksum: 10/ab6ac2e562d083faac7d8152ec1cc4eccc80f62e9579b69ed40aedf7211a6b2d57024a6cd53c4e35fd051c39a236e86257d1d99ebdb122291969a0a04563b51e +"@esbuild/darwin-x64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/darwin-x64@npm:0.25.4" + conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@jest/environment@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/environment@npm:29.7.0" - dependencies: - "@jest/fake-timers": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - jest-mock: "npm:^29.7.0" - checksum: 10/90b5844a9a9d8097f2cf107b1b5e57007c552f64315da8c1f51217eeb0a9664889d3f145cdf8acf23a84f4d8309a6675e27d5b059659a004db0ea9546d1c81a8 +"@esbuild/freebsd-arm64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/freebsd-arm64@npm:0.25.4" + conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@jest/expect-utils@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/expect-utils@npm:29.7.0" - dependencies: - jest-get-type: "npm:^29.6.3" - checksum: 10/ef8d379778ef574a17bde2801a6f4469f8022a46a5f9e385191dc73bb1fc318996beaed4513fbd7055c2847227a1bed2469977821866534593a6e52a281499ee +"@esbuild/freebsd-x64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/freebsd-x64@npm:0.25.4" + conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@jest/expect@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/expect@npm:29.7.0" - dependencies: - expect: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - checksum: 10/fea6c3317a8da5c840429d90bfe49d928e89c9e89fceee2149b93a11b7e9c73d2f6e4d7cdf647163da938fc4e2169e4490be6bae64952902bc7a701033fd4880 +"@esbuild/linux-arm64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/linux-arm64@npm:0.25.4" + conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@jest/fake-timers@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/fake-timers@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - "@sinonjs/fake-timers": "npm:^10.0.2" - "@types/node": "npm:*" - jest-message-util: "npm:^29.7.0" - jest-mock: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - checksum: 10/9b394e04ffc46f91725ecfdff34c4e043eb7a16e1d78964094c9db3fde0b1c8803e45943a980e8c740d0a3d45661906de1416ca5891a538b0660481a3a828c27 +"@esbuild/linux-arm@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/linux-arm@npm:0.25.4" + conditions: os=linux & cpu=arm languageName: node linkType: hard -"@jest/globals@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/globals@npm:29.7.0" - dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/expect": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - jest-mock: "npm:^29.7.0" - checksum: 10/97dbb9459135693ad3a422e65ca1c250f03d82b2a77f6207e7fa0edd2c9d2015fbe4346f3dc9ebff1678b9d8da74754d4d440b7837497f8927059c0642a22123 +"@esbuild/linux-ia32@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/linux-ia32@npm:0.25.4" + conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@jest/reporters@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/reporters@npm:29.7.0" - dependencies: - "@bcoe/v8-coverage": "npm:^0.2.3" - "@jest/console": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@jridgewell/trace-mapping": "npm:^0.3.18" - "@types/node": "npm:*" - chalk: "npm:^4.0.0" - collect-v8-coverage: "npm:^1.0.0" - exit: "npm:^0.1.2" - glob: "npm:^7.1.3" - graceful-fs: "npm:^4.2.9" - istanbul-lib-coverage: "npm:^3.0.0" - istanbul-lib-instrument: "npm:^6.0.0" - istanbul-lib-report: "npm:^3.0.0" - istanbul-lib-source-maps: "npm:^4.0.0" - istanbul-reports: "npm:^3.1.3" - jest-message-util: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-worker: "npm:^29.7.0" - slash: "npm:^3.0.0" - string-length: "npm:^4.0.1" - strip-ansi: "npm:^6.0.0" - v8-to-istanbul: "npm:^9.0.1" - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - checksum: 10/a17d1644b26dea14445cedd45567f4ba7834f980be2ef74447204e14238f121b50d8b858fde648083d2cd8f305f81ba434ba49e37a5f4237a6f2a61180cc73dc +"@esbuild/linux-loong64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/linux-loong64@npm:0.25.4" + conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@jest/schemas@npm:^29.6.3": - version: 29.6.3 - resolution: "@jest/schemas@npm:29.6.3" - dependencies: - "@sinclair/typebox": "npm:^0.27.8" - checksum: 10/910040425f0fc93cd13e68c750b7885590b8839066dfa0cd78e7def07bbb708ad869381f725945d66f2284de5663bbecf63e8fdd856e2ae6e261ba30b1687e93 +"@esbuild/linux-mips64el@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/linux-mips64el@npm:0.25.4" + conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@jest/source-map@npm:^29.6.3": - version: 29.6.3 - resolution: "@jest/source-map@npm:29.6.3" - dependencies: - "@jridgewell/trace-mapping": "npm:^0.3.18" - callsites: "npm:^3.0.0" - graceful-fs: "npm:^4.2.9" - checksum: 10/bcc5a8697d471396c0003b0bfa09722c3cd879ad697eb9c431e6164e2ea7008238a01a07193dfe3cbb48b1d258eb7251f6efcea36f64e1ebc464ea3c03ae2deb +"@esbuild/linux-ppc64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/linux-ppc64@npm:0.25.4" + conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@jest/test-result@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/test-result@npm:29.7.0" - dependencies: - "@jest/console": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/istanbul-lib-coverage": "npm:^2.0.0" - collect-v8-coverage: "npm:^1.0.0" - checksum: 10/c073ab7dfe3c562bff2b8fee6cc724ccc20aa96bcd8ab48ccb2aa309b4c0c1923a9e703cea386bd6ae9b71133e92810475bb9c7c22328fc63f797ad3324ed189 +"@esbuild/linux-riscv64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/linux-riscv64@npm:0.25.4" + conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@jest/test-sequencer@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/test-sequencer@npm:29.7.0" - dependencies: - "@jest/test-result": "npm:^29.7.0" - graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.7.0" - slash: "npm:^3.0.0" - checksum: 10/4420c26a0baa7035c5419b0892ff8ffe9a41b1583ec54a10db3037cd46a7e29dd3d7202f8aa9d376e9e53be5f8b1bc0d16e1de6880a6d319b033b01dc4c8f639 +"@esbuild/linux-s390x@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/linux-s390x@npm:0.25.4" + conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@jest/transform@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/transform@npm:29.7.0" - dependencies: - "@babel/core": "npm:^7.11.6" - "@jest/types": "npm:^29.6.3" - "@jridgewell/trace-mapping": "npm:^0.3.18" - babel-plugin-istanbul: "npm:^6.1.1" - chalk: "npm:^4.0.0" - convert-source-map: "npm:^2.0.0" - fast-json-stable-stringify: "npm:^2.1.0" - graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.7.0" - jest-regex-util: "npm:^29.6.3" - jest-util: "npm:^29.7.0" - micromatch: "npm:^4.0.4" - pirates: "npm:^4.0.4" - slash: "npm:^3.0.0" - write-file-atomic: "npm:^4.0.2" - checksum: 10/30f42293545ab037d5799c81d3e12515790bb58513d37f788ce32d53326d0d72ebf5b40f989e6896739aa50a5f77be44686e510966370d58511d5ad2637c68c1 - languageName: node - linkType: hard - -"@jest/types@npm:^29.6.3": - version: 29.6.3 - resolution: "@jest/types@npm:29.6.3" +"@esbuild/linux-x64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/linux-x64@npm:0.25.4" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-arm64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/netbsd-arm64@npm:0.25.4" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/netbsd-x64@npm:0.25.4" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/openbsd-arm64@npm:0.25.4" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/openbsd-x64@npm:0.25.4" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/sunos-x64@npm:0.25.4" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/win32-arm64@npm:0.25.4" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/win32-ia32@npm:0.25.4" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.25.4": + version: 0.25.4 + resolution: "@esbuild/win32-x64@npm:0.25.4" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@isaacs/cliui@npm:^8.0.2": + version: 8.0.2 + resolution: "@isaacs/cliui@npm:8.0.2" dependencies: - "@jest/schemas": "npm:^29.6.3" - "@types/istanbul-lib-coverage": "npm:^2.0.0" - "@types/istanbul-reports": "npm:^3.0.0" - "@types/node": "npm:*" - "@types/yargs": "npm:^17.0.8" - chalk: "npm:^4.0.0" - checksum: 10/f74bf512fd09bbe2433a2ad460b04668b7075235eea9a0c77d6a42222c10a79b9747dc2b2a623f140ed40d6865a2ed8f538f3cbb75169120ea863f29a7ed76cd + string-width: "npm:^5.1.2" + string-width-cjs: "npm:string-width@^4.2.0" + strip-ansi: "npm:^7.0.1" + strip-ansi-cjs: "npm:strip-ansi@^6.0.1" + wrap-ansi: "npm:^8.1.0" + wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" + checksum: 10/e9ed5fd27c3aec1095e3a16e0c0cf148d1fee55a38665c35f7b3f86a9b5d00d042ddaabc98e8a1cb7463b9378c15f22a94eb35e99469c201453eb8375191f243 languageName: node linkType: hard -"@jridgewell/gen-mapping@npm:^0.3.5": - version: 0.3.8 - resolution: "@jridgewell/gen-mapping@npm:0.3.8" +"@isaacs/fs-minipass@npm:^4.0.0": + version: 4.0.1 + resolution: "@isaacs/fs-minipass@npm:4.0.1" dependencies: - "@jridgewell/set-array": "npm:^1.2.1" - "@jridgewell/sourcemap-codec": "npm:^1.4.10" - "@jridgewell/trace-mapping": "npm:^0.3.24" - checksum: 10/9d3a56ab3612ab9b85d38b2a93b87f3324f11c5130859957f6500e4ac8ce35f299d5ccc3ecd1ae87597601ecf83cee29e9afd04c18777c24011073992ff946df + minipass: "npm:^7.0.4" + checksum: 10/4412e9e6713c89c1e66d80bb0bb5a2a93192f10477623a27d08f228ba0316bb880affabc5bfe7f838f58a34d26c2c190da726e576cdfc18c49a72e89adabdcf5 languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": +"@jridgewell/resolve-uri@npm:^3.0.3": version: 3.1.2 resolution: "@jridgewell/resolve-uri@npm:3.1.2" checksum: 10/97106439d750a409c22c8bff822d648f6a71f3aa9bc8e5129efdc36343cd3096ddc4eeb1c62d2fe48e9bdd4db37b05d4646a17114ecebd3bbcacfa2de51c3c1d languageName: node linkType: hard -"@jridgewell/set-array@npm:^1.2.1": - version: 1.2.1 - resolution: "@jridgewell/set-array@npm:1.2.1" - checksum: 10/832e513a85a588f8ed4f27d1279420d8547743cc37fcad5a5a76fc74bb895b013dfe614d0eed9cb860048e6546b798f8f2652020b4b2ba0561b05caa8c654b10 - languageName: node - linkType: hard - -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.5.0": version: 1.5.0 resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" checksum: 10/4ed6123217569a1484419ac53f6ea0d9f3b57e5b57ab30d7c267bdb27792a27eb0e4b08e84a2680aa55cc2f2b411ffd6ec3db01c44fdc6dc43aca4b55f8374fd @@ -799,45 +327,35 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": - version: 0.3.25 - resolution: "@jridgewell/trace-mapping@npm:0.3.25" - dependencies: - "@jridgewell/resolve-uri": "npm:^3.1.0" - "@jridgewell/sourcemap-codec": "npm:^1.4.14" - checksum: 10/dced32160a44b49d531b80a4a2159dceab6b3ddf0c8e95a0deae4b0e894b172defa63d5ac52a19c2068e1fe7d31ea4ba931fbeec103233ecb4208953967120fc - languageName: node - linkType: hard - -"@midnight-ntwrk/compact-runtime@npm:^0.7.0": - version: 0.7.0 - resolution: "@midnight-ntwrk/compact-runtime@npm:0.7.0" +"@midnight-ntwrk/compact-runtime@npm:^0.8.0": + version: 0.8.1 + resolution: "@midnight-ntwrk/compact-runtime@npm:0.8.1" dependencies: - "@midnight-ntwrk/onchain-runtime": "npm:^0.2.0" + "@midnight-ntwrk/onchain-runtime": "npm:^0.3.0" "@types/object-inspect": "npm:^1.8.1" object-inspect: "npm:^1.12.3" - checksum: 10/9d390a7edd89e08439de546d6431b30d89c8fb85f1254cb0389c99b1f9a5d0613d0ecdd65b374deb84a5ae017f37306395692244742500db4b8dab37427b4611 + checksum: 10/caec8b65018e38e1fac35d6d5538d5203152948411b72121185ea7bea601f616fd32dd65851acceff3435c472b22ec7d6919916f64d03de6096ae952967f55e1 languageName: node linkType: hard -"@midnight-ntwrk/ledger@npm:^3.0.6": - version: 3.0.6 - resolution: "@midnight-ntwrk/ledger@npm:3.0.6" - checksum: 10/644fac9ea7b47c8d0c8ea437e18e2362746701e2fedba3f6fa9a08dcea1f283c05336d9def60403e72055baa5a1e841f971a858ae3133b577a3f12518a48c753 +"@midnight-ntwrk/ledger@npm:^4.0.0": + version: 4.0.0 + resolution: "@midnight-ntwrk/ledger@npm:4.0.0" + checksum: 10/826f6d2743af2a3f199f1ad61cb946a529eb5755dfc68ea7f8fc436bb366716bd5118a4561ed541938caa9db6f366b7c9ee8047511f41e5bcaaf21c335d29b1d languageName: node linkType: hard -"@midnight-ntwrk/onchain-runtime@npm:^0.2.0": - version: 0.2.6 - resolution: "@midnight-ntwrk/onchain-runtime@npm:0.2.6" - checksum: 10/6c7bf8a6d9dfd4560f1da67a0b0a2a89331eecb8110b07f7d2eab1c311cadc8f5fc42e46118649766490e534b504c0e7cad94cfdcccdbb1b09d9f69877707ebd +"@midnight-ntwrk/onchain-runtime@npm:^0.3.0": + version: 0.3.0 + resolution: "@midnight-ntwrk/onchain-runtime@npm:0.3.0" + checksum: 10/e0d6a9a96314dbce99345b9794395682a3471568fde13d90122227f52082dba7b83dc05d419e4745e5bf997e93274c2a01f3938ccd20351de8249923c0c9ab45 languageName: node linkType: hard -"@midnight-ntwrk/zswap@npm:^3.0.6": - version: 3.0.6 - resolution: "@midnight-ntwrk/zswap@npm:3.0.6" - checksum: 10/d095b9380d1ca9f0f94286ce31bd8aaee0ee6458d8681d5b021198c1125e9e9276ebf7bd6ca5221c800ec1d8ed27909faf866268e3673d36a5126c2c9b99b595 +"@midnight-ntwrk/zswap@npm:^4.0.0": + version: 4.0.0 + resolution: "@midnight-ntwrk/zswap@npm:4.0.0" + checksum: 10/20a8ded6e0683a1f9d979ba7593b09f0c29504f4f0144efba0efea3136acef5b2d3855a1c1a430487c490b0f31a6f5382d8c6d0482342da28e0cf59398a1ccf3 languageName: node linkType: hard @@ -867,15 +385,11 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/compact@workspace:compact" dependencies: - "@types/jest": "npm:^29.5.6" "@types/node": "npm:^22.13.10" chalk: "npm:^5.4.1" fast-check: "npm:^3.15.0" - jest: "npm:^29.7.0" - jest-fast-check: "npm:^2.0.0" log-symbols: "npm:^7.0.0" ora: "npm:^8.2.0" - ts-jest: "npm:^29.1.1" typescript: "npm:^5.8.2" bin: compact-builder: dist/runBuilder.js @@ -889,10 +403,11 @@ __metadata: dependencies: "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" - "@types/jest": "npm:^29.5.6" "@types/node": "npm:^18.18.6" - jest: "npm:^29.7.0" + "@vitest/ui": "npm:^3.1.3" + ts-node: "npm:^10.9.2" typescript: "npm:^5.2.2" + vitest: "npm:^3.1.3" languageName: unknown linkType: soft @@ -902,10 +417,11 @@ __metadata: dependencies: "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" - "@types/jest": "npm:^29.5.6" "@types/node": "npm:^18.18.6" - jest: "npm:^29.7.0" + "@vitest/ui": "npm:^3.1.3" + ts-node: "npm:^10.9.2" typescript: "npm:^5.2.2" + vitest: "npm:^3.1.3" languageName: unknown linkType: soft @@ -916,33 +432,155 @@ __metadata: languageName: node linkType: hard -"@sinclair/typebox@npm:^0.27.8": - version: 0.27.8 - resolution: "@sinclair/typebox@npm:0.27.8" - checksum: 10/297f95ff77c82c54de8c9907f186076e715ff2621c5222ba50b8d40a170661c0c5242c763cba2a4791f0f91cb1d8ffa53ea1d7294570cf8cd4694c0e383e484d +"@polka/url@npm:^1.0.0-next.24": + version: 1.0.0-next.29 + resolution: "@polka/url@npm:1.0.0-next.29" + checksum: 10/69ca11ab15a4ffec7f0b07fcc4e1f01489b3d9683a7e1867758818386575c60c213401259ba3705b8a812228d17e2bfd18e6f021194d943fff4bca389c9d4f28 languageName: node linkType: hard -"@sinonjs/commons@npm:^3.0.0": - version: 3.0.1 - resolution: "@sinonjs/commons@npm:3.0.1" - dependencies: - type-detect: "npm:4.0.8" - checksum: 10/a0af217ba7044426c78df52c23cedede6daf377586f3ac58857c565769358ab1f44ebf95ba04bbe38814fba6e316ca6f02870a009328294fc2c555d0f85a7117 +"@rollup/rollup-android-arm-eabi@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.40.2" + conditions: os=android & cpu=arm languageName: node linkType: hard -"@sinonjs/fake-timers@npm:^10.0.2": - version: 10.3.0 - resolution: "@sinonjs/fake-timers@npm:10.3.0" - dependencies: - "@sinonjs/commons": "npm:^3.0.0" - checksum: 10/78155c7bd866a85df85e22028e046b8d46cf3e840f72260954f5e3ed5bd97d66c595524305a6841ffb3f681a08f6e5cef572a2cce5442a8a232dc29fb409b83e +"@rollup/rollup-android-arm64@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-android-arm64@npm:4.40.2" + conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@tsconfig/node10@npm:^1.0.7": - version: 1.0.11 +"@rollup/rollup-darwin-arm64@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-darwin-arm64@npm:4.40.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-x64@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-darwin-x64@npm:4.40.2" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-arm64@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.40.2" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-x64@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-freebsd-x64@npm:4.40.2" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-gnueabihf@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.40.2" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.40.2" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.40.2" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-musl@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.40.2" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-loongarch64-gnu@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.40.2" + conditions: os=linux & cpu=loong64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.40.2" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.40.2" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-musl@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.40.2" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.40.2" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.40.2" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-musl@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.40.2" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.40.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-ia32-msvc@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.40.2" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.40.2": + version: 4.40.2 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.40.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@tsconfig/node10@npm:^1.0.7": + version: 1.0.11 resolution: "@tsconfig/node10@npm:1.0.11" checksum: 10/51fe47d55fe1b80ec35e6e5ed30a13665fd3a531945350aa74a14a1e82875fb60b350c2f2a5e72a64831b1b6bc02acb6760c30b3738b54954ec2dea82db7a267 languageName: node @@ -969,136 +607,133 @@ __metadata: languageName: node linkType: hard -"@types/babel__core@npm:^7.1.14": - version: 7.20.5 - resolution: "@types/babel__core@npm:7.20.5" - dependencies: - "@babel/parser": "npm:^7.20.7" - "@babel/types": "npm:^7.20.7" - "@types/babel__generator": "npm:*" - "@types/babel__template": "npm:*" - "@types/babel__traverse": "npm:*" - checksum: 10/c32838d280b5ab59d62557f9e331d3831f8e547ee10b4f85cb78753d97d521270cebfc73ce501e9fb27fe71884d1ba75e18658692c2f4117543f0fc4e3e118b3 +"@types/estree@npm:1.0.7, @types/estree@npm:^1.0.0": + version: 1.0.7 + resolution: "@types/estree@npm:1.0.7" + checksum: 10/419c845ece767ad4b21171e6e5b63dabb2eb46b9c0d97361edcd9cabbf6a95fcadb91d89b5fa098d1336fa0b8fceaea82fca97a2ef3971f5c86e53031e157b21 languageName: node linkType: hard -"@types/babel__generator@npm:*": - version: 7.27.0 - resolution: "@types/babel__generator@npm:7.27.0" +"@types/node@npm:^18.18.6": + version: 18.19.87 + resolution: "@types/node@npm:18.19.87" dependencies: - "@babel/types": "npm:^7.0.0" - checksum: 10/f572e67a9a39397664350a4437d8a7fbd34acc83ff4887a8cf08349e39f8aeb5ad2f70fb78a0a0a23a280affe3a5f4c25f50966abdce292bcf31237af1c27b1a + undici-types: "npm:~5.26.4" + checksum: 10/1e71b6d16dedeaa1fd5ff55baf1f353ca1f9e673b2e482d7fe82fa685addea5159a36602a344784c989b5e07ca1be633d0c493adf5951dee5a29cee69d613e7f languageName: node linkType: hard -"@types/babel__template@npm:*": - version: 7.4.4 - resolution: "@types/babel__template@npm:7.4.4" +"@types/node@npm:^22.13.10": + version: 22.15.2 + resolution: "@types/node@npm:22.15.2" dependencies: - "@babel/parser": "npm:^7.1.0" - "@babel/types": "npm:^7.0.0" - checksum: 10/d7a02d2a9b67e822694d8e6a7ddb8f2b71a1d6962dfd266554d2513eefbb205b33ca71a0d163b1caea3981ccf849211f9964d8bd0727124d18ace45aa6c9ae29 + undici-types: "npm:~6.21.0" + checksum: 10/e22071571205413518aa3710644ed9603d8f4a417fc59f0e180240e1c05aaf7fb8feecdf553a2da305247b3533d03b58eab6e333115f01f581b9139a6b1dcd47 languageName: node linkType: hard -"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6": - version: 7.20.7 - resolution: "@types/babel__traverse@npm:7.20.7" - dependencies: - "@babel/types": "npm:^7.20.7" - checksum: 10/d005b58e1c26bdafc1ce564f60db0ee938393c7fc586b1197bdb71a02f7f33f72bc10ae4165776b6cafc77c4b6f2e1a164dd20bc36518c471b1131b153b4baa6 +"@types/object-inspect@npm:^1.8.1": + version: 1.13.0 + resolution: "@types/object-inspect@npm:1.13.0" + checksum: 10/8caf52c815947540b5246e0b5b2d455a2183791fe9427537eab8a40b465392400cee6ce50beaeb35465e167e9cb405ccfde90eb5317ee2c9df85af7508f0a320 languageName: node linkType: hard -"@types/graceful-fs@npm:^4.1.3": - version: 4.1.9 - resolution: "@types/graceful-fs@npm:4.1.9" +"@vitest/expect@npm:3.1.3": + version: 3.1.3 + resolution: "@vitest/expect@npm:3.1.3" dependencies: - "@types/node": "npm:*" - checksum: 10/79d746a8f053954bba36bd3d94a90c78de995d126289d656fb3271dd9f1229d33f678da04d10bce6be440494a5a73438e2e363e92802d16b8315b051036c5256 - languageName: node - linkType: hard - -"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": - version: 2.0.6 - resolution: "@types/istanbul-lib-coverage@npm:2.0.6" - checksum: 10/3feac423fd3e5449485afac999dcfcb3d44a37c830af898b689fadc65d26526460bedb889db278e0d4d815a670331796494d073a10ee6e3a6526301fe7415778 + "@vitest/spy": "npm:3.1.3" + "@vitest/utils": "npm:3.1.3" + chai: "npm:^5.2.0" + tinyrainbow: "npm:^2.0.0" + checksum: 10/f63053849430e93e85cd50994a75f32e6b73d35fefbf7894f1869c356ed6c601adfc95c66004b2df3c49335300202286480c47d841d78d2047af6bee00f8b3ed languageName: node linkType: hard -"@types/istanbul-lib-report@npm:*": - version: 3.0.3 - resolution: "@types/istanbul-lib-report@npm:3.0.3" +"@vitest/mocker@npm:3.1.3": + version: 3.1.3 + resolution: "@vitest/mocker@npm:3.1.3" dependencies: - "@types/istanbul-lib-coverage": "npm:*" - checksum: 10/b91e9b60f865ff08cb35667a427b70f6c2c63e88105eadd29a112582942af47ed99c60610180aa8dcc22382fa405033f141c119c69b95db78c4c709fbadfeeb4 + "@vitest/spy": "npm:3.1.3" + estree-walker: "npm:^3.0.3" + magic-string: "npm:^0.30.17" + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + checksum: 10/fc4a8ee015551f476af56ee27327c78fd6f8a023eea79a92834482d10272c74dd0a39631b2d55341e54ac04803b1d2710527b34ed206ede18cde9706a1582ed8 languageName: node linkType: hard -"@types/istanbul-reports@npm:^3.0.0": - version: 3.0.4 - resolution: "@types/istanbul-reports@npm:3.0.4" +"@vitest/pretty-format@npm:3.1.3, @vitest/pretty-format@npm:^3.1.3": + version: 3.1.3 + resolution: "@vitest/pretty-format@npm:3.1.3" dependencies: - "@types/istanbul-lib-report": "npm:*" - checksum: 10/93eb18835770b3431f68ae9ac1ca91741ab85f7606f310a34b3586b5a34450ec038c3eed7ab19266635499594de52ff73723a54a72a75b9f7d6a956f01edee95 + tinyrainbow: "npm:^2.0.0" + checksum: 10/da508750f47b4043e9aaea803f37dada4d3121b63a8fd2a7c77849a380d9040ca488291f6ee98e7ee3e6543bd6c2ed7cdad99b6b86897999c740462ef617413a languageName: node linkType: hard -"@types/jest@npm:^29.5.6": - version: 29.5.14 - resolution: "@types/jest@npm:29.5.14" +"@vitest/runner@npm:3.1.3": + version: 3.1.3 + resolution: "@vitest/runner@npm:3.1.3" dependencies: - expect: "npm:^29.0.0" - pretty-format: "npm:^29.0.0" - checksum: 10/59ec7a9c4688aae8ee529316c43853468b6034f453d08a2e1064b281af9c81234cec986be796288f1bbb29efe943bc950e70c8fa8faae1e460d50e3cf9760f9b + "@vitest/utils": "npm:3.1.3" + pathe: "npm:^2.0.3" + checksum: 10/7862077b7663200801cd7903b977b3713a291f91b2b0930ee59951bec0ae51d38219308e543b62ff5eaed9ead51bcbd7175b19f9b7c0d876e2975defee76fdee languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^22.13.10": - version: 22.15.2 - resolution: "@types/node@npm:22.15.2" +"@vitest/snapshot@npm:3.1.3": + version: 3.1.3 + resolution: "@vitest/snapshot@npm:3.1.3" dependencies: - undici-types: "npm:~6.21.0" - checksum: 10/e22071571205413518aa3710644ed9603d8f4a417fc59f0e180240e1c05aaf7fb8feecdf553a2da305247b3533d03b58eab6e333115f01f581b9139a6b1dcd47 + "@vitest/pretty-format": "npm:3.1.3" + magic-string: "npm:^0.30.17" + pathe: "npm:^2.0.3" + checksum: 10/5889414ecd19df6a1cc09c57fc96d344721f01e5812d9153565208c76dac4d42fc1c636153b9701d50a1d5acd4fd8ce81c09c9592d97728a700c5a8af790d0a4 languageName: node linkType: hard -"@types/node@npm:^18.18.6": - version: 18.19.87 - resolution: "@types/node@npm:18.19.87" +"@vitest/spy@npm:3.1.3": + version: 3.1.3 + resolution: "@vitest/spy@npm:3.1.3" dependencies: - undici-types: "npm:~5.26.4" - checksum: 10/1e71b6d16dedeaa1fd5ff55baf1f353ca1f9e673b2e482d7fe82fa685addea5159a36602a344784c989b5e07ca1be633d0c493adf5951dee5a29cee69d613e7f - languageName: node - linkType: hard - -"@types/object-inspect@npm:^1.8.1": - version: 1.13.0 - resolution: "@types/object-inspect@npm:1.13.0" - checksum: 10/8caf52c815947540b5246e0b5b2d455a2183791fe9427537eab8a40b465392400cee6ce50beaeb35465e167e9cb405ccfde90eb5317ee2c9df85af7508f0a320 - languageName: node - linkType: hard - -"@types/stack-utils@npm:^2.0.0": - version: 2.0.3 - resolution: "@types/stack-utils@npm:2.0.3" - checksum: 10/72576cc1522090fe497337c2b99d9838e320659ac57fa5560fcbdcbafcf5d0216c6b3a0a8a4ee4fdb3b1f5e3420aa4f6223ab57b82fef3578bec3206425c6cf5 + tinyspy: "npm:^3.0.2" + checksum: 10/9b42e219b40fde935e5bd7fa19ee99f01fc27ecd89a5fccabbbbc91e02eef3bd0530ba3769c2ff380529f708eb535a30cce773d680c708209a994c54d1d992fe languageName: node linkType: hard -"@types/yargs-parser@npm:*": - version: 21.0.3 - resolution: "@types/yargs-parser@npm:21.0.3" - checksum: 10/a794eb750e8ebc6273a51b12a0002de41343ffe46befef460bdbb57262d187fdf608bc6615b7b11c462c63c3ceb70abe2564c8dd8ee0f7628f38a314f74a9b9b +"@vitest/ui@npm:^3.1.3": + version: 3.1.3 + resolution: "@vitest/ui@npm:3.1.3" + dependencies: + "@vitest/utils": "npm:3.1.3" + fflate: "npm:^0.8.2" + flatted: "npm:^3.3.3" + pathe: "npm:^2.0.3" + sirv: "npm:^3.0.1" + tinyglobby: "npm:^0.2.13" + tinyrainbow: "npm:^2.0.0" + peerDependencies: + vitest: 3.1.3 + checksum: 10/e59b6772b21b97d64428746adc81cf61bf8b04a72bb6178504d8fff2dd02f50e8daada8815f6351f9575dbb8e7880b0dfff2a363b3beee4d9475a4402dcb4afe languageName: node linkType: hard -"@types/yargs@npm:^17.0.8": - version: 17.0.33 - resolution: "@types/yargs@npm:17.0.33" +"@vitest/utils@npm:3.1.3": + version: 3.1.3 + resolution: "@vitest/utils@npm:3.1.3" dependencies: - "@types/yargs-parser": "npm:*" - checksum: 10/16f6681bf4d99fb671bf56029141ed01db2862e3db9df7fc92d8bea494359ac96a1b4b1c35a836d1e95e665fb18ad753ab2015fc0db663454e8fd4e5d5e2ef91 + "@vitest/pretty-format": "npm:3.1.3" + loupe: "npm:^3.1.3" + tinyrainbow: "npm:^2.0.0" + checksum: 10/d9971948161364e61e0fb08a053b9768f02054686f0a74e5b7bdc9c726271842d5f8c4256c68cf9aad2b83a28d2333c5694e336715d145e194fa1a93e64e97c3 languageName: node linkType: hard @@ -1134,15 +769,6 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^4.2.1": - version: 4.3.2 - resolution: "ansi-escapes@npm:4.3.2" - dependencies: - type-fest: "npm:^0.21.3" - checksum: 10/8661034456193ffeda0c15c8c564a9636b0c04094b7f78bd01517929c17c504090a60f7a75f949f5af91289c264d3e1001d91492c1bd58efc8e100500ce04de2 - languageName: node - linkType: hard - "ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" @@ -1157,7 +783,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": +"ansi-styles@npm:^4.0.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: @@ -1166,13 +792,6 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^5.0.0": - version: 5.2.0 - resolution: "ansi-styles@npm:5.2.0" - checksum: 10/d7f4e97ce0623aea6bc0d90dcd28881ee04cba06c570b97fd3391bd7a268eedfd9d5e2dd4fdcbdd82b8105df5faf6f24aaedc08eaf3da898e702db5948f63469 - languageName: node - linkType: hard - "ansi-styles@npm:^6.1.0": version: 6.2.1 resolution: "ansi-styles@npm:6.2.1" @@ -1180,16 +799,6 @@ __metadata: languageName: node linkType: hard -"anymatch@npm:^3.0.3": - version: 3.1.3 - resolution: "anymatch@npm:3.1.3" - dependencies: - normalize-path: "npm:^3.0.0" - picomatch: "npm:^2.0.4" - checksum: 10/3e044fd6d1d26545f235a9fe4d7a534e2029d8e59fa7fd9f2a6eb21230f6b5380ea1eaf55136e60cbf8e613544b3b766e7a6fa2102e2a3a117505466e3025dc2 - languageName: node - linkType: hard - "arg@npm:^4.1.0": version: 4.1.3 resolution: "arg@npm:4.1.3" @@ -1197,98 +806,10 @@ __metadata: languageName: node linkType: hard -"argparse@npm:^1.0.7": - version: 1.0.10 - resolution: "argparse@npm:1.0.10" - dependencies: - sprintf-js: "npm:~1.0.2" - checksum: 10/c6a621343a553ff3779390bb5ee9c2263d6643ebcd7843227bdde6cc7adbed796eb5540ca98db19e3fd7b4714e1faa51551f8849b268bb62df27ddb15cbcd91e - languageName: node - linkType: hard - -"async@npm:^3.2.3": - version: 3.2.6 - resolution: "async@npm:3.2.6" - checksum: 10/cb6e0561a3c01c4b56a799cc8bab6ea5fef45f069ab32500b6e19508db270ef2dffa55e5aed5865c5526e9907b1f8be61b27530823b411ffafb5e1538c86c368 - languageName: node - linkType: hard - -"babel-jest@npm:^29.7.0": - version: 29.7.0 - resolution: "babel-jest@npm:29.7.0" - dependencies: - "@jest/transform": "npm:^29.7.0" - "@types/babel__core": "npm:^7.1.14" - babel-plugin-istanbul: "npm:^6.1.1" - babel-preset-jest: "npm:^29.6.3" - chalk: "npm:^4.0.0" - graceful-fs: "npm:^4.2.9" - slash: "npm:^3.0.0" - peerDependencies: - "@babel/core": ^7.8.0 - checksum: 10/8a0953bd813b3a8926008f7351611055548869e9a53dd36d6e7e96679001f71e65fd7dbfe253265c3ba6a4e630dc7c845cf3e78b17d758ef1880313ce8fba258 - languageName: node - linkType: hard - -"babel-plugin-istanbul@npm:^6.1.1": - version: 6.1.1 - resolution: "babel-plugin-istanbul@npm:6.1.1" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.0.0" - "@istanbuljs/load-nyc-config": "npm:^1.0.0" - "@istanbuljs/schema": "npm:^0.1.2" - istanbul-lib-instrument: "npm:^5.0.4" - test-exclude: "npm:^6.0.0" - checksum: 10/ffd436bb2a77bbe1942a33245d770506ab2262d9c1b3c1f1da7f0592f78ee7445a95bc2efafe619dd9c1b6ee52c10033d6c7d29ddefe6f5383568e60f31dfe8d - languageName: node - linkType: hard - -"babel-plugin-jest-hoist@npm:^29.6.3": - version: 29.6.3 - resolution: "babel-plugin-jest-hoist@npm:29.6.3" - dependencies: - "@babel/template": "npm:^7.3.3" - "@babel/types": "npm:^7.3.3" - "@types/babel__core": "npm:^7.1.14" - "@types/babel__traverse": "npm:^7.0.6" - checksum: 10/9bfa86ec4170bd805ab8ca5001ae50d8afcb30554d236ba4a7ffc156c1a92452e220e4acbd98daefc12bf0216fccd092d0a2efed49e7e384ec59e0597a926d65 - languageName: node - linkType: hard - -"babel-preset-current-node-syntax@npm:^1.0.0": - version: 1.1.0 - resolution: "babel-preset-current-node-syntax@npm:1.1.0" - dependencies: - "@babel/plugin-syntax-async-generators": "npm:^7.8.4" - "@babel/plugin-syntax-bigint": "npm:^7.8.3" - "@babel/plugin-syntax-class-properties": "npm:^7.12.13" - "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" - "@babel/plugin-syntax-import-attributes": "npm:^7.24.7" - "@babel/plugin-syntax-import-meta": "npm:^7.10.4" - "@babel/plugin-syntax-json-strings": "npm:^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" - "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" - "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" - "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" - "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" - "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" - "@babel/plugin-syntax-top-level-await": "npm:^7.14.5" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/46331111ae72b7121172fd9e6a4a7830f651ad44bf26dbbf77b3c8a60a18009411a3eacb5e72274004290c110371230272109957d5224d155436b4794ead2f1b - languageName: node - linkType: hard - -"babel-preset-jest@npm:^29.6.3": - version: 29.6.3 - resolution: "babel-preset-jest@npm:29.6.3" - dependencies: - babel-plugin-jest-hoist: "npm:^29.6.3" - babel-preset-current-node-syntax: "npm:^1.0.0" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/aa4ff2a8a728d9d698ed521e3461a109a1e66202b13d3494e41eea30729a5e7cc03b3a2d56c594423a135429c37bf63a9fa8b0b9ce275298be3095a88c69f6fb +"assertion-error@npm:^2.0.1": + version: 2.0.1 + resolution: "assertion-error@npm:2.0.1" + checksum: 10/a0789dd882211b87116e81e2648ccb7f60340b34f19877dd020b39ebb4714e475eb943e14ba3e22201c221ef6645b7bfe10297e76b6ac95b48a9898c1211ce66 languageName: node linkType: hard @@ -1299,16 +820,6 @@ __metadata: languageName: node linkType: hard -"brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" - dependencies: - balanced-match: "npm:^1.0.0" - concat-map: "npm:0.0.1" - checksum: 10/faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 - languageName: node - linkType: hard - "brace-expansion@npm:^2.0.1": version: 2.0.1 resolution: "brace-expansion@npm:2.0.1" @@ -1318,51 +829,10 @@ __metadata: languageName: node linkType: hard -"braces@npm:^3.0.3": - version: 3.0.3 - resolution: "braces@npm:3.0.3" - dependencies: - fill-range: "npm:^7.1.1" - checksum: 10/fad11a0d4697a27162840b02b1fad249c1683cbc510cd5bf1a471f2f8085c046d41094308c577a50a03a579dd99d5a6b3724c4b5e8b14df2c4443844cfcda2c6 - languageName: node - linkType: hard - -"browserslist@npm:^4.24.0": - version: 4.24.4 - resolution: "browserslist@npm:4.24.4" - dependencies: - caniuse-lite: "npm:^1.0.30001688" - electron-to-chromium: "npm:^1.5.73" - node-releases: "npm:^2.0.19" - update-browserslist-db: "npm:^1.1.1" - bin: - browserslist: cli.js - checksum: 10/11fda105e803d891311a21a1f962d83599319165faf471c2d70e045dff82a12128f5b50b1fcba665a2352ad66147aaa248a9d2355a80aadc3f53375eb3de2e48 - languageName: node - linkType: hard - -"bs-logger@npm:^0.2.6": - version: 0.2.6 - resolution: "bs-logger@npm:0.2.6" - dependencies: - fast-json-stable-stringify: "npm:2.x" - checksum: 10/e6d3ff82698bb3f20ce64fb85355c5716a3cf267f3977abe93bf9c32a2e46186b253f48a028ae5b96ab42bacd2c826766d9ae8cf6892f9b944656be9113cf212 - languageName: node - linkType: hard - -"bser@npm:2.1.1": - version: 2.1.1 - resolution: "bser@npm:2.1.1" - dependencies: - node-int64: "npm:^0.4.0" - checksum: 10/edba1b65bae682450be4117b695997972bd9a3c4dfee029cab5bcb72ae5393a79a8f909b8bc77957eb0deec1c7168670f18f4d5c556f46cdd3bca5f3b3a8d020 - languageName: node - linkType: hard - -"buffer-from@npm:^1.0.0": - version: 1.1.2 - resolution: "buffer-from@npm:1.1.2" - checksum: 10/0448524a562b37d4d7ed9efd91685a5b77a50672c556ea254ac9a6d30e3403a517d8981f10e565db24e8339413b43c97ca2951f10e399c6125a0d8911f5679bb +"cac@npm:^6.7.14": + version: 6.7.14 + resolution: "cac@npm:6.7.14" + checksum: 10/002769a0fbfc51c062acd2a59df465a2a947916b02ac50b56c69ec6c018ee99ac3e7f4dd7366334ea847f1ecacf4defaa61bcd2ac283db50156ce1f1d8c8ad42 languageName: node linkType: hard @@ -1386,41 +856,16 @@ __metadata: languageName: node linkType: hard -"callsites@npm:^3.0.0": - version: 3.1.0 - resolution: "callsites@npm:3.1.0" - checksum: 10/072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 - languageName: node - linkType: hard - -"camelcase@npm:^5.3.1": - version: 5.3.1 - resolution: "camelcase@npm:5.3.1" - checksum: 10/e6effce26b9404e3c0f301498184f243811c30dfe6d0b9051863bd8e4034d09c8c2923794f280d6827e5aa055f6c434115ff97864a16a963366fb35fd673024b - languageName: node - linkType: hard - -"camelcase@npm:^6.2.0": - version: 6.3.0 - resolution: "camelcase@npm:6.3.0" - checksum: 10/8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001688": - version: 1.0.30001715 - resolution: "caniuse-lite@npm:1.0.30001715" - checksum: 10/5608cdaf609eb5fe3a86ab6c1c2f3943dbdab813041725f4747f5432b05e6e19fc606faa8a9b75c329b37b772c91c47e8db483e76a6b715b59c289ce53dcba68 - languageName: node - linkType: hard - -"chalk@npm:^4.0.0, chalk@npm:^4.0.2": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" +"chai@npm:^5.2.0": + version: 5.2.0 + resolution: "chai@npm:5.2.0" dependencies: - ansi-styles: "npm:^4.1.0" - supports-color: "npm:^7.1.0" - checksum: 10/cb3f3e594913d63b1814d7ca7c9bafbf895f75fbf93b92991980610dfd7b48500af4e3a5d4e3a8f337990a96b168d7eb84ee55efdce965e2ee8efc20f8c8f139 + assertion-error: "npm:^2.0.1" + check-error: "npm:^2.1.1" + deep-eql: "npm:^5.0.1" + loupe: "npm:^3.1.0" + pathval: "npm:^2.0.0" + checksum: 10/2ce03671c159c6a567bf1912756daabdbb7c075f3c0078f1b59d61da8d276936367ee696dfe093b49e1479d9ba93a6074c8e55d49791dddd8061728cdcad249e languageName: node linkType: hard @@ -1431,10 +876,10 @@ __metadata: languageName: node linkType: hard -"char-regex@npm:^1.0.2": - version: 1.0.2 - resolution: "char-regex@npm:1.0.2" - checksum: 10/1ec5c2906adb9f84e7f6732a40baef05d7c85401b82ffcbc44b85fbd0f7a2b0c2a96f2eb9cf55cae3235dc12d4023003b88f09bcae8be9ae894f52ed746f4d48 +"check-error@npm:^2.1.1": + version: 2.1.1 + resolution: "check-error@npm:2.1.1" + checksum: 10/d785ed17b1d4a4796b6e75c765a9a290098cf52ff9728ce0756e8ffd4293d2e419dd30c67200aee34202463b474306913f2fcfaf1890641026d9fc6966fea27a languageName: node linkType: hard @@ -1445,20 +890,6 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^3.2.0": - version: 3.9.0 - resolution: "ci-info@npm:3.9.0" - checksum: 10/75bc67902b4d1c7b435497adeb91598f6d52a3389398e44294f6601b20cfef32cf2176f7be0eb961d9e085bb333a8a5cae121cb22f81cf238ae7f58eb80e9397 - languageName: node - linkType: hard - -"cjs-module-lexer@npm:^1.0.0": - version: 1.4.3 - resolution: "cjs-module-lexer@npm:1.4.3" - checksum: 10/d2b92f919a2dedbfd61d016964fce8da0035f827182ed6839c97cac56e8a8077cfa6a59388adfe2bc588a19cef9bbe830d683a76a6e93c51f65852062cfe2591 - languageName: node - linkType: hard - "cli-cursor@npm:^5.0.0": version: 5.0.0 resolution: "cli-cursor@npm:5.0.0" @@ -1475,31 +906,6 @@ __metadata: languageName: node linkType: hard -"cliui@npm:^8.0.1": - version: 8.0.1 - resolution: "cliui@npm:8.0.1" - dependencies: - string-width: "npm:^4.2.0" - strip-ansi: "npm:^6.0.1" - wrap-ansi: "npm:^7.0.0" - checksum: 10/eaa5561aeb3135c2cddf7a3b3f562fc4238ff3b3fc666869ef2adf264be0f372136702f16add9299087fb1907c2e4ec5dbfe83bd24bce815c70a80c6c1a2e950 - languageName: node - linkType: hard - -"co@npm:^4.6.0": - version: 4.6.0 - resolution: "co@npm:4.6.0" - checksum: 10/a5d9f37091c70398a269e625cedff5622f200ed0aa0cff22ee7b55ed74a123834b58711776eb0f1dc58eb6ebbc1185aa7567b57bd5979a948c6e4f85073e2c05 - languageName: node - linkType: hard - -"collect-v8-coverage@npm:^1.0.0": - version: 1.0.2 - resolution: "collect-v8-coverage@npm:1.0.2" - checksum: 10/30ea7d5c9ee51f2fdba4901d4186c5b7114a088ef98fd53eda3979da77eed96758a2cae81cc6d97e239aaea6065868cf908b24980663f7b7e96aa291b3e12fa4 - languageName: node - linkType: hard - "color-convert@npm:^2.0.1": version: 2.0.1 resolution: "color-convert@npm:2.0.1" @@ -1516,37 +922,6 @@ __metadata: languageName: node linkType: hard -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 10/9680699c8e2b3af0ae22592cb764acaf973f292a7b71b8a06720233011853a58e256c89216a10cbe889727532fd77f8bcd49a760cedfde271b8e006c20e079f2 - languageName: node - linkType: hard - -"convert-source-map@npm:^2.0.0": - version: 2.0.0 - resolution: "convert-source-map@npm:2.0.0" - checksum: 10/c987be3ec061348cdb3c2bfb924bec86dea1eacad10550a85ca23edb0fe3556c3a61c7399114f3331ccb3499d7fd0285ab24566e5745929412983494c3926e15 - languageName: node - linkType: hard - -"create-jest@npm:^29.7.0": - version: 29.7.0 - resolution: "create-jest@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - chalk: "npm:^4.0.0" - exit: "npm:^0.1.2" - graceful-fs: "npm:^4.2.9" - jest-config: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - prompts: "npm:^2.0.1" - bin: - create-jest: bin/create-jest.js - checksum: 10/847b4764451672b4174be4d5c6d7d63442ec3aa5f3de52af924e4d996d87d7801c18e125504f25232fc75840f6625b3ac85860fac6ce799b5efae7bdcaf4a2b7 - languageName: node - linkType: hard - "create-require@npm:^1.1.0": version: 1.1.1 resolution: "create-require@npm:1.1.1" @@ -1554,7 +929,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": +"cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -1565,48 +940,22 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.4": - version: 4.4.0 - resolution: "debug@npm:4.4.0" +"debug@npm:4, debug@npm:^4.3.4, debug@npm:^4.4.0": + version: 4.4.1 + resolution: "debug@npm:4.4.1" dependencies: ms: "npm:^2.1.3" peerDependenciesMeta: supports-color: optional: true - checksum: 10/1847944c2e3c2c732514b93d11886575625686056cd765336212dc15de2d2b29612b6cd80e1afba767bb8e1803b778caf9973e98169ef1a24a7a7009e1820367 - languageName: node - linkType: hard - -"dedent@npm:^1.0.0": - version: 1.5.3 - resolution: "dedent@npm:1.5.3" - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - checksum: 10/e5277f6268f288649503125b781a7b7a2c9b22d011139688c0b3619fe40121e600eb1f077c891938d4b2428bdb6326cc3c77a763e4b1cc681bd9666ab1bad2a1 - languageName: node - linkType: hard - -"deepmerge@npm:^4.2.2": - version: 4.3.1 - resolution: "deepmerge@npm:4.3.1" - checksum: 10/058d9e1b0ff1a154468bf3837aea436abcfea1ba1d165ddaaf48ca93765fdd01a30d33c36173da8fbbed951dd0a267602bc782fe288b0fc4b7e1e7091afc4529 - languageName: node - linkType: hard - -"detect-newline@npm:^3.0.0": - version: 3.1.0 - resolution: "detect-newline@npm:3.1.0" - checksum: 10/ae6cd429c41ad01b164c59ea36f264a2c479598e61cba7c99da24175a7ab80ddf066420f2bec9a1c57a6bead411b4655ff15ad7d281c000a89791f48cbe939e7 + checksum: 10/8e2709b2144f03c7950f8804d01ccb3786373df01e406a0f66928e47001cf2d336cbed9ee137261d4f90d68d8679468c755e3548ed83ddacdc82b194d2468afe languageName: node linkType: hard -"diff-sequences@npm:^29.6.3": - version: 29.6.3 - resolution: "diff-sequences@npm:29.6.3" - checksum: 10/179daf9d2f9af5c57ad66d97cb902a538bcf8ed64963fa7aa0c329b3de3665ce2eb6ffdc2f69f29d445fa4af2517e5e55e5b6e00c00a9ae4f43645f97f7078cb +"deep-eql@npm:^5.0.1": + version: 5.0.2 + resolution: "deep-eql@npm:5.0.2" + checksum: 10/a529b81e2ef8821621d20a36959a0328873a3e49d393ad11f8efe8559f31239494c2eb889b80342808674c475802ba95b9d6c4c27641b9a029405104c1b59fcf languageName: node linkType: hard @@ -1624,31 +973,6 @@ __metadata: languageName: node linkType: hard -"ejs@npm:^3.1.10": - version: 3.1.10 - resolution: "ejs@npm:3.1.10" - dependencies: - jake: "npm:^10.8.5" - bin: - ejs: bin/cli.js - checksum: 10/a9cb7d7cd13b7b1cd0be5c4788e44dd10d92f7285d2f65b942f33e127230c054f99a42db4d99f766d8dbc6c57e94799593ee66a14efd7c8dd70c4812bf6aa384 - languageName: node - linkType: hard - -"electron-to-chromium@npm:^1.5.73": - version: 1.5.143 - resolution: "electron-to-chromium@npm:1.5.143" - checksum: 10/91a7980f96da5ad33b77e95c7e628f468e6bb53eac41437612882810a7552514132728f7c34ee5c967c599557af491fcc4f75e9138f82d22c1b1cdfc63fb8d6b - languageName: node - linkType: hard - -"emittery@npm:^0.13.1": - version: 0.13.1 - resolution: "emittery@npm:0.13.1" - checksum: 10/fbe214171d878b924eedf1757badf58a5dce071cd1fa7f620fa841a0901a80d6da47ff05929d53163105e621ce11a71b9d8acb1148ffe1745e045145f6e69521 - languageName: node - linkType: hard - "emoji-regex@npm:^10.3.0": version: 10.4.0 resolution: "emoji-regex@npm:10.4.0" @@ -1693,1096 +1017,337 @@ __metadata: languageName: node linkType: hard -"error-ex@npm:^1.3.1": - version: 1.3.2 - resolution: "error-ex@npm:1.3.2" - dependencies: - is-arrayish: "npm:^0.2.1" - checksum: 10/d547740aa29c34e753fb6fed2c5de81802438529c12b3673bd37b6bb1fe49b9b7abdc3c11e6062fe625d8a296b3cf769a80f878865e25e685f787763eede3ffb - languageName: node - linkType: hard - -"escalade@npm:^3.1.1, escalade@npm:^3.2.0": - version: 3.2.0 - resolution: "escalade@npm:3.2.0" - checksum: 10/9d7169e3965b2f9ae46971afa392f6e5a25545ea30f2e2dd99c9b0a95a3f52b5653681a84f5b2911a413ddad2d7a93d3514165072f349b5ffc59c75a899970d6 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^2.0.0": - version: 2.0.0 - resolution: "escape-string-regexp@npm:2.0.0" - checksum: 10/9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 - languageName: node - linkType: hard - -"esprima@npm:^4.0.0": - version: 4.0.1 - resolution: "esprima@npm:4.0.1" - bin: - esparse: ./bin/esparse.js - esvalidate: ./bin/esvalidate.js - checksum: 10/f1d3c622ad992421362294f7acf866aa9409fbad4eb2e8fa230bd33944ce371d32279667b242d8b8907ec2b6ad7353a717f3c0e60e748873a34a7905174bc0eb - languageName: node - linkType: hard - -"execa@npm:^5.0.0": - version: 5.1.1 - resolution: "execa@npm:5.1.1" - dependencies: - cross-spawn: "npm:^7.0.3" - get-stream: "npm:^6.0.0" - human-signals: "npm:^2.1.0" - is-stream: "npm:^2.0.0" - merge-stream: "npm:^2.0.0" - npm-run-path: "npm:^4.0.1" - onetime: "npm:^5.1.2" - signal-exit: "npm:^3.0.3" - strip-final-newline: "npm:^2.0.0" - checksum: 10/8ada91f2d70f7dff702c861c2c64f21dfdc1525628f3c0454fd6f02fce65f7b958616cbd2b99ca7fa4d474e461a3d363824e91b3eb881705231abbf387470597 - languageName: node - linkType: hard - -"exit@npm:^0.1.2": - version: 0.1.2 - resolution: "exit@npm:0.1.2" - checksum: 10/387555050c5b3c10e7a9e8df5f43194e95d7737c74532c409910e585d5554eaff34960c166643f5e23d042196529daad059c292dcf1fb61b8ca878d3677f4b87 - languageName: node - linkType: hard - -"expect@npm:^29.0.0, expect@npm:^29.7.0": - version: 29.7.0 - resolution: "expect@npm:29.7.0" - dependencies: - "@jest/expect-utils": "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - jest-matcher-utils: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - checksum: 10/63f97bc51f56a491950fb525f9ad94f1916e8a014947f8d8445d3847a665b5471b768522d659f5e865db20b6c2033d2ac10f35fcbd881a4d26407a4f6f18451a - languageName: node - linkType: hard - -"exponential-backoff@npm:^3.1.1": - version: 3.1.2 - resolution: "exponential-backoff@npm:3.1.2" - checksum: 10/ca2f01f1aa4dafd3f3917bd531ab5be08c6f5f4b2389d2e974f903de3cbeb50b9633374353516b6afd70905775e33aba11afab1232d3acf0aa2963b98a611c51 - languageName: node - linkType: hard - -"fast-check@npm:^3.15.0": - version: 3.23.2 - resolution: "fast-check@npm:3.23.2" - dependencies: - pure-rand: "npm:^6.1.0" - checksum: 10/dab344146b778e8bc2973366ea55528d1b58d3e3037270262b877c54241e800c4d744957722c24705c787020d702aece11e57c9e3dbd5ea19c3e10926bf1f3fe - languageName: node - linkType: hard - -"fast-json-stable-stringify@npm:2.x, fast-json-stable-stringify@npm:^2.1.0": - version: 2.1.0 - resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: 10/2c20055c1fa43c922428f16ca8bb29f2807de63e5c851f665f7ac9790176c01c3b40335257736b299764a8d383388dabc73c8083b8e1bc3d99f0a941444ec60e - languageName: node - linkType: hard - -"fb-watchman@npm:^2.0.0": - version: 2.0.2 - resolution: "fb-watchman@npm:2.0.2" - dependencies: - bser: "npm:2.1.1" - checksum: 10/4f95d336fb805786759e383fd7fff342ceb7680f53efcc0ef82f502eb479ce35b98e8b207b6dfdfeea0eba845862107dc73813775fc6b56b3098c6e90a2dad77 - languageName: node - linkType: hard - -"fdir@npm:^6.4.4": - version: 6.4.4 - resolution: "fdir@npm:6.4.4" - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - checksum: 10/d0000d6b790059b35f4ed19acc8847a66452e0bc68b28766c929ffd523e5ec2083811fc8a545e4a1d4945ce70e887b3a610c145c681073b506143ae3076342ed - languageName: node - linkType: hard - -"filelist@npm:^1.0.4": - version: 1.0.4 - resolution: "filelist@npm:1.0.4" - dependencies: - minimatch: "npm:^5.0.1" - checksum: 10/4b436fa944b1508b95cffdfc8176ae6947b92825483639ef1b9a89b27d82f3f8aa22b21eed471993f92709b431670d4e015b39c087d435a61e1bb04564cf51de - languageName: node - linkType: hard - -"fill-range@npm:^7.1.1": - version: 7.1.1 - resolution: "fill-range@npm:7.1.1" - dependencies: - to-regex-range: "npm:^5.0.1" - checksum: 10/a7095cb39e5bc32fada2aa7c7249d3f6b01bd1ce461a61b0adabacccabd9198500c6fb1f68a7c851a657e273fce2233ba869638897f3d7ed2e87a2d89b4436ea - languageName: node - linkType: hard - -"find-up@npm:^4.0.0, find-up@npm:^4.1.0": - version: 4.1.0 - resolution: "find-up@npm:4.1.0" - dependencies: - locate-path: "npm:^5.0.0" - path-exists: "npm:^4.0.0" - checksum: 10/4c172680e8f8c1f78839486e14a43ef82e9decd0e74145f40707cc42e7420506d5ec92d9a11c22bd2c48fb0c384ea05dd30e10dd152fefeec6f2f75282a8b844 - languageName: node - linkType: hard - -"foreground-child@npm:^3.1.0": - version: 3.3.1 - resolution: "foreground-child@npm:3.3.1" - dependencies: - cross-spawn: "npm:^7.0.6" - signal-exit: "npm:^4.0.1" - checksum: 10/427b33f997a98073c0424e5c07169264a62cda806d8d2ded159b5b903fdfc8f0a1457e06b5fc35506497acb3f1e353f025edee796300209ac6231e80edece835 - languageName: node - linkType: hard - -"fs-minipass@npm:^3.0.0": - version: 3.0.3 - resolution: "fs-minipass@npm:3.0.3" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/af143246cf6884fe26fa281621d45cfe111d34b30535a475bfa38dafe343dadb466c047a924ffc7d6b7b18265df4110224ce3803806dbb07173bf2087b648d7f - languageName: node - linkType: hard - -"fs.realpath@npm:^1.0.0": - version: 1.0.0 - resolution: "fs.realpath@npm:1.0.0" - checksum: 10/e703107c28e362d8d7b910bbcbfd371e640a3bb45ae157a362b5952c0030c0b6d4981140ec319b347bce7adc025dd7813da1ff908a945ac214d64f5402a51b96 - languageName: node - linkType: hard - -"fsevents@npm:^2.3.2": - version: 2.3.3 - resolution: "fsevents@npm:2.3.3" - dependencies: - node-gyp: "npm:latest" - checksum: 10/4c1ade961ded57cdbfbb5cac5106ec17bc8bccd62e16343c569a0ceeca83b9dfef87550b4dc5cbb89642da412b20c5071f304c8c464b80415446e8e155a038c0 - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin": - version: 2.3.3 - resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" - dependencies: - node-gyp: "npm:latest" - conditions: os=darwin - languageName: node - linkType: hard - -"function-bind@npm:^1.1.2": - version: 1.1.2 - resolution: "function-bind@npm:1.1.2" - checksum: 10/185e20d20f10c8d661d59aac0f3b63b31132d492e1b11fcc2a93cb2c47257ebaee7407c38513efd2b35cafdf972d9beb2ea4593c1e0f3bf8f2744836928d7454 - languageName: node - linkType: hard - -"gensync@npm:^1.0.0-beta.2": - version: 1.0.0-beta.2 - resolution: "gensync@npm:1.0.0-beta.2" - checksum: 10/17d8333460204fbf1f9160d067e1e77f908a5447febb49424b8ab043026049835c9ef3974445c57dbd39161f4d2b04356d7de12b2eecaa27a7a7ea7d871cbedd - languageName: node - linkType: hard - -"get-caller-file@npm:^2.0.5": - version: 2.0.5 - resolution: "get-caller-file@npm:2.0.5" - checksum: 10/b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9 - languageName: node - linkType: hard - -"get-east-asian-width@npm:^1.0.0": - version: 1.3.0 - resolution: "get-east-asian-width@npm:1.3.0" - checksum: 10/8e8e779eb28701db7fdb1c8cab879e39e6ae23f52dadd89c8aed05869671cee611a65d4f8557b83e981428623247d8bc5d0c7a4ef3ea7a41d826e73600112ad8 - languageName: node - linkType: hard - -"get-package-type@npm:^0.1.0": - version: 0.1.0 - resolution: "get-package-type@npm:0.1.0" - checksum: 10/bba0811116d11e56d702682ddef7c73ba3481f114590e705fc549f4d868972263896af313c57a25c076e3c0d567e11d919a64ba1b30c879be985fc9d44f96148 - languageName: node - linkType: hard - -"get-stream@npm:^6.0.0": - version: 6.0.1 - resolution: "get-stream@npm:6.0.1" - checksum: 10/781266d29725f35c59f1d214aedc92b0ae855800a980800e2923b3fbc4e56b3cb6e462c42e09a1cf1a00c64e056a78fa407cbe06c7c92b7e5cd49b4b85c2a497 - languageName: node - linkType: hard - -"glob@npm:^10.2.2": - version: 10.4.5 - resolution: "glob@npm:10.4.5" - dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^3.1.2" - minimatch: "npm:^9.0.4" - minipass: "npm:^7.1.2" - package-json-from-dist: "npm:^1.0.0" - path-scurry: "npm:^1.11.1" - bin: - glob: dist/esm/bin.mjs - checksum: 10/698dfe11828b7efd0514cd11e573eaed26b2dff611f0400907281ce3eab0c1e56143ef9b35adc7c77ecc71fba74717b510c7c223d34ca8a98ec81777b293d4ac - languageName: node - linkType: hard - -"glob@npm:^7.1.3, glob@npm:^7.1.4": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^3.1.1" - once: "npm:^1.3.0" - path-is-absolute: "npm:^1.0.0" - checksum: 10/59452a9202c81d4508a43b8af7082ca5c76452b9fcc4a9ab17655822e6ce9b21d4f8fbadabe4fe3faef448294cec249af305e2cd824b7e9aaf689240e5e96a7b - languageName: node - linkType: hard - -"globals@npm:^11.1.0": - version: 11.12.0 - resolution: "globals@npm:11.12.0" - checksum: 10/9f054fa38ff8de8fa356502eb9d2dae0c928217b8b5c8de1f09f5c9b6c8a96d8b9bd3afc49acbcd384a98a81fea713c859e1b09e214c60509517bb8fc2bc13c2 - languageName: node - linkType: hard - -"graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 - languageName: node - linkType: hard - -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 10/261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad - languageName: node - linkType: hard - -"hasown@npm:^2.0.2": - version: 2.0.2 - resolution: "hasown@npm:2.0.2" - dependencies: - function-bind: "npm:^1.1.2" - checksum: 10/7898a9c1788b2862cf0f9c345a6bec77ba4a0c0983c7f19d610c382343d4f98fa260686b225dfb1f88393a66679d2ec58ee310c1d6868c081eda7918f32cc70a - languageName: node - linkType: hard - -"html-escaper@npm:^2.0.0": - version: 2.0.2 - resolution: "html-escaper@npm:2.0.2" - checksum: 10/034d74029dcca544a34fb6135e98d427acd73019796ffc17383eaa3ec2fe1c0471dcbbc8f8ed39e46e86d43ccd753a160631615e4048285e313569609b66d5b7 - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.1.1": - version: 4.1.1 - resolution: "http-cache-semantics@npm:4.1.1" - checksum: 10/362d5ed66b12ceb9c0a328fb31200b590ab1b02f4a254a697dc796850cc4385603e75f53ec59f768b2dad3bfa1464bd229f7de278d2899a0e3beffc634b6683f - languageName: node - linkType: hard - -"http-proxy-agent@npm:^7.0.0": - version: 7.0.2 - resolution: "http-proxy-agent@npm:7.0.2" - dependencies: - agent-base: "npm:^7.1.0" - debug: "npm:^4.3.4" - checksum: 10/d062acfa0cb82beeb558f1043c6ba770ea892b5fb7b28654dbc70ea2aeea55226dd34c02a294f6c1ca179a5aa483c4ea641846821b182edbd9cc5d89b54c6848 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^7.0.1": - version: 7.0.6 - resolution: "https-proxy-agent@npm:7.0.6" - dependencies: - agent-base: "npm:^7.1.2" - debug: "npm:4" - checksum: 10/784b628cbd55b25542a9d85033bdfd03d4eda630fb8b3c9477959367f3be95dc476ed2ecbb9836c359c7c698027fc7b45723a302324433590f45d6c1706e8c13 - languageName: node - linkType: hard - -"human-signals@npm:^2.1.0": - version: 2.1.0 - resolution: "human-signals@npm:2.1.0" - checksum: 10/df59be9e0af479036798a881d1f136c4a29e0b518d4abb863afbd11bf30efa3eeb1d0425fc65942dcc05ab3bf40205ea436b0ff389f2cd20b75b8643d539bf86 - languageName: node - linkType: hard - -"iconv-lite@npm:^0.6.2": - version: 0.6.3 - resolution: "iconv-lite@npm:0.6.3" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10/24e3292dd3dadaa81d065c6f8c41b274a47098150d444b96e5f53b4638a9a71482921ea6a91a1f59bb71d9796de25e04afd05919fa64c360347ba65d3766f10f - languageName: node - linkType: hard - -"import-local@npm:^3.0.2": - version: 3.2.0 - resolution: "import-local@npm:3.2.0" - dependencies: - pkg-dir: "npm:^4.2.0" - resolve-cwd: "npm:^3.0.0" - bin: - import-local-fixture: fixtures/cli.js - checksum: 10/0b0b0b412b2521739fbb85eeed834a3c34de9bc67e670b3d0b86248fc460d990a7b116ad056c084b87a693ef73d1f17268d6a5be626bb43c998a8b1c8a230004 - languageName: node - linkType: hard - -"imurmurhash@npm:^0.1.4": - version: 0.1.4 - resolution: "imurmurhash@npm:0.1.4" - checksum: 10/2d30b157a91fe1c1d7c6f653cbf263f039be6c5bfa959245a16d4ee191fc0f2af86c08545b6e6beeb041c56b574d2d5b9f95343d378ab49c0f37394d541e7fc8 - languageName: node - linkType: hard - -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: "npm:^1.3.0" - wrappy: "npm:1" - checksum: 10/d2ebd65441a38c8336c223d1b80b921b9fa737e37ea466fd7e253cb000c64ae1f17fa59e68130ef5bda92cfd8d36b83d37dab0eb0a4558bcfec8e8cdfd2dcb67 - languageName: node - linkType: hard - -"inherits@npm:2": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 10/cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521 - languageName: node - linkType: hard - -"ip-address@npm:^9.0.5": - version: 9.0.5 - resolution: "ip-address@npm:9.0.5" - dependencies: - jsbn: "npm:1.1.0" - sprintf-js: "npm:^1.1.3" - checksum: 10/1ed81e06721af012306329b31f532b5e24e00cb537be18ddc905a84f19fe8f83a09a1699862bf3a1ec4b9dea93c55a3fa5faf8b5ea380431469df540f38b092c - languageName: node - linkType: hard - -"is-arrayish@npm:^0.2.1": - version: 0.2.1 - resolution: "is-arrayish@npm:0.2.1" - checksum: 10/73ced84fa35e59e2c57da2d01e12cd01479f381d7f122ce41dcbb713f09dbfc651315832cd2bf8accba7681a69e4d6f1e03941d94dd10040d415086360e7005e - languageName: node - linkType: hard - -"is-core-module@npm:^2.16.0": - version: 2.16.1 - resolution: "is-core-module@npm:2.16.1" - dependencies: - hasown: "npm:^2.0.2" - checksum: 10/452b2c2fb7f889cbbf7e54609ef92cf6c24637c568acc7e63d166812a0fb365ae8a504c333a29add8bdb1686704068caa7f4e4b639b650dde4f00a038b8941fb - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^3.0.0": - version: 3.0.0 - resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: 10/44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 - languageName: node - linkType: hard - -"is-generator-fn@npm:^2.0.0": - version: 2.1.0 - resolution: "is-generator-fn@npm:2.1.0" - checksum: 10/a6ad5492cf9d1746f73b6744e0c43c0020510b59d56ddcb78a91cbc173f09b5e6beff53d75c9c5a29feb618bfef2bf458e025ecf3a57ad2268e2fb2569f56215 - languageName: node - linkType: hard - -"is-interactive@npm:^2.0.0": - version: 2.0.0 - resolution: "is-interactive@npm:2.0.0" - checksum: 10/e8d52ad490bed7ae665032c7675ec07732bbfe25808b0efbc4d5a76b1a1f01c165f332775c63e25e9a03d319ebb6b24f571a9e902669fc1e40b0a60b5be6e26c - languageName: node - linkType: hard - -"is-number@npm:^7.0.0": - version: 7.0.0 - resolution: "is-number@npm:7.0.0" - checksum: 10/6a6c3383f68afa1e05b286af866017c78f1226d43ac8cb064e115ff9ed85eb33f5c4f7216c96a71e4dfea289ef52c5da3aef5bbfade8ffe47a0465d70c0c8e86 - languageName: node - linkType: hard - -"is-stream@npm:^2.0.0": - version: 2.0.1 - resolution: "is-stream@npm:2.0.1" - checksum: 10/b8e05ccdf96ac330ea83c12450304d4a591f9958c11fd17bed240af8d5ffe08aedafa4c0f4cfccd4d28dc9d4d129daca1023633d5c11601a6cbc77521f6fae66 - languageName: node - linkType: hard - -"is-unicode-supported@npm:^1.3.0": - version: 1.3.0 - resolution: "is-unicode-supported@npm:1.3.0" - checksum: 10/20a1fc161afafaf49243551a5ac33b6c4cf0bbcce369fcd8f2951fbdd000c30698ce320de3ee6830497310a8f41880f8066d440aa3eb0a853e2aa4836dd89abc - languageName: node - linkType: hard - -"is-unicode-supported@npm:^2.0.0": - version: 2.1.0 - resolution: "is-unicode-supported@npm:2.1.0" - checksum: 10/f254e3da6b0ab1a57a94f7273a7798dd35d1d45b227759f600d0fa9d5649f9c07fa8d3c8a6360b0e376adf916d151ec24fc9a50c5295c58bae7ca54a76a063f9 - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 10/7c9f715c03aff08f35e98b1fadae1b9267b38f0615d501824f9743f3aab99ef10e303ce7db3f186763a0b70a19de5791ebfc854ff884d5a8c4d92211f642ec92 - languageName: node - linkType: hard - -"isexe@npm:^3.1.1": - version: 3.1.1 - resolution: "isexe@npm:3.1.1" - checksum: 10/7fe1931ee4e88eb5aa524cd3ceb8c882537bc3a81b02e438b240e47012eef49c86904d0f0e593ea7c3a9996d18d0f1f3be8d3eaa92333977b0c3a9d353d5563e - languageName: node - linkType: hard - -"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": - version: 3.2.2 - resolution: "istanbul-lib-coverage@npm:3.2.2" - checksum: 10/40bbdd1e937dfd8c830fa286d0f665e81b7a78bdabcd4565f6d5667c99828bda3db7fb7ac6b96a3e2e8a2461ddbc5452d9f8bc7d00cb00075fa6a3e99f5b6a81 - languageName: node - linkType: hard - -"istanbul-lib-instrument@npm:^5.0.4": - version: 5.2.1 - resolution: "istanbul-lib-instrument@npm:5.2.1" - dependencies: - "@babel/core": "npm:^7.12.3" - "@babel/parser": "npm:^7.14.7" - "@istanbuljs/schema": "npm:^0.1.2" - istanbul-lib-coverage: "npm:^3.2.0" - semver: "npm:^6.3.0" - checksum: 10/bbc4496c2f304d799f8ec22202ab38c010ac265c441947f075c0f7d46bd440b45c00e46017cf9053453d42182d768b1d6ed0e70a142c95ab00df9843aa5ab80e - languageName: node - linkType: hard - -"istanbul-lib-instrument@npm:^6.0.0": - version: 6.0.3 - resolution: "istanbul-lib-instrument@npm:6.0.3" - dependencies: - "@babel/core": "npm:^7.23.9" - "@babel/parser": "npm:^7.23.9" - "@istanbuljs/schema": "npm:^0.1.3" - istanbul-lib-coverage: "npm:^3.2.0" - semver: "npm:^7.5.4" - checksum: 10/aa5271c0008dfa71b6ecc9ba1e801bf77b49dc05524e8c30d58aaf5b9505e0cd12f25f93165464d4266a518c5c75284ecb598fbd89fec081ae77d2c9d3327695 - languageName: node - linkType: hard - -"istanbul-lib-report@npm:^3.0.0": - version: 3.0.1 - resolution: "istanbul-lib-report@npm:3.0.1" - dependencies: - istanbul-lib-coverage: "npm:^3.0.0" - make-dir: "npm:^4.0.0" - supports-color: "npm:^7.1.0" - checksum: 10/86a83421ca1cf2109a9f6d193c06c31ef04a45e72a74579b11060b1e7bb9b6337a4e6f04abfb8857e2d569c271273c65e855ee429376a0d7c91ad91db42accd1 - languageName: node - linkType: hard - -"istanbul-lib-source-maps@npm:^4.0.0": - version: 4.0.1 - resolution: "istanbul-lib-source-maps@npm:4.0.1" - dependencies: - debug: "npm:^4.1.1" - istanbul-lib-coverage: "npm:^3.0.0" - source-map: "npm:^0.6.1" - checksum: 10/5526983462799aced011d776af166e350191b816821ea7bcf71cab3e5272657b062c47dc30697a22a43656e3ced78893a42de677f9ccf276a28c913190953b82 - languageName: node - linkType: hard - -"istanbul-reports@npm:^3.1.3": - version: 3.1.7 - resolution: "istanbul-reports@npm:3.1.7" - dependencies: - html-escaper: "npm:^2.0.0" - istanbul-lib-report: "npm:^3.0.0" - checksum: 10/f1faaa4684efaf57d64087776018d7426312a59aa6eeb4e0e3a777347d23cd286ad18f427e98f0e3dee666103d7404c9d7abc5f240406a912fa16bd6695437fa - languageName: node - linkType: hard - -"jackspeak@npm:^3.1.2": - version: 3.4.3 - resolution: "jackspeak@npm:3.4.3" - dependencies: - "@isaacs/cliui": "npm:^8.0.2" - "@pkgjs/parseargs": "npm:^0.11.0" +"es-module-lexer@npm:^1.7.0": + version: 1.7.0 + resolution: "es-module-lexer@npm:1.7.0" + checksum: 10/b6f3e576a3fed4d82b0d0ad4bbf6b3a5ad694d2e7ce8c4a069560da3db6399381eaba703616a182b16dde50ce998af64e07dcf49f2ae48153b9e07be3f107087 + languageName: node + linkType: hard + +"esbuild@npm:^0.25.0": + version: 0.25.4 + resolution: "esbuild@npm:0.25.4" + dependencies: + "@esbuild/aix-ppc64": "npm:0.25.4" + "@esbuild/android-arm": "npm:0.25.4" + "@esbuild/android-arm64": "npm:0.25.4" + "@esbuild/android-x64": "npm:0.25.4" + "@esbuild/darwin-arm64": "npm:0.25.4" + "@esbuild/darwin-x64": "npm:0.25.4" + "@esbuild/freebsd-arm64": "npm:0.25.4" + "@esbuild/freebsd-x64": "npm:0.25.4" + "@esbuild/linux-arm": "npm:0.25.4" + "@esbuild/linux-arm64": "npm:0.25.4" + "@esbuild/linux-ia32": "npm:0.25.4" + "@esbuild/linux-loong64": "npm:0.25.4" + "@esbuild/linux-mips64el": "npm:0.25.4" + "@esbuild/linux-ppc64": "npm:0.25.4" + "@esbuild/linux-riscv64": "npm:0.25.4" + "@esbuild/linux-s390x": "npm:0.25.4" + "@esbuild/linux-x64": "npm:0.25.4" + "@esbuild/netbsd-arm64": "npm:0.25.4" + "@esbuild/netbsd-x64": "npm:0.25.4" + "@esbuild/openbsd-arm64": "npm:0.25.4" + "@esbuild/openbsd-x64": "npm:0.25.4" + "@esbuild/sunos-x64": "npm:0.25.4" + "@esbuild/win32-arm64": "npm:0.25.4" + "@esbuild/win32-ia32": "npm:0.25.4" + "@esbuild/win32-x64": "npm:0.25.4" dependenciesMeta: - "@pkgjs/parseargs": + "@esbuild/aix-ppc64": optional: true - checksum: 10/96f8786eaab98e4bf5b2a5d6d9588ea46c4d06bbc4f2eb861fdd7b6b182b16f71d8a70e79820f335d52653b16d4843b29dd9cdcf38ae80406756db9199497cf3 - languageName: node - linkType: hard - -"jake@npm:^10.8.5": - version: 10.9.2 - resolution: "jake@npm:10.9.2" - dependencies: - async: "npm:^3.2.3" - chalk: "npm:^4.0.2" - filelist: "npm:^1.0.4" - minimatch: "npm:^3.1.2" - bin: - jake: bin/cli.js - checksum: 10/3be324708f99f031e0aec49ef8fd872eb4583cbe8a29a0c875f554f6ac638ee4ea5aa759bb63723fd54f77ca6d7db851eaa78353301734ed3700db9cb109a0cd - languageName: node - linkType: hard - -"jest-changed-files@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-changed-files@npm:29.7.0" - dependencies: - execa: "npm:^5.0.0" - jest-util: "npm:^29.7.0" - p-limit: "npm:^3.1.0" - checksum: 10/3d93742e56b1a73a145d55b66e96711fbf87ef89b96c2fab7cfdfba8ec06612591a982111ca2b712bb853dbc16831ec8b43585a2a96b83862d6767de59cbf83d - languageName: node - linkType: hard - -"jest-circus@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-circus@npm:29.7.0" - dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/expect": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - chalk: "npm:^4.0.0" - co: "npm:^4.6.0" - dedent: "npm:^1.0.0" - is-generator-fn: "npm:^2.0.0" - jest-each: "npm:^29.7.0" - jest-matcher-utils: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-runtime: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - p-limit: "npm:^3.1.0" - pretty-format: "npm:^29.7.0" - pure-rand: "npm:^6.0.0" - slash: "npm:^3.0.0" - stack-utils: "npm:^2.0.3" - checksum: 10/716a8e3f40572fd0213bcfc1da90274bf30d856e5133af58089a6ce45089b63f4d679bd44e6be9d320e8390483ebc3ae9921981993986d21639d9019b523123d - languageName: node - linkType: hard - -"jest-cli@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-cli@npm:29.7.0" - dependencies: - "@jest/core": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - chalk: "npm:^4.0.0" - create-jest: "npm:^29.7.0" - exit: "npm:^0.1.2" - import-local: "npm:^3.0.2" - jest-config: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - yargs: "npm:^17.3.1" - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: + "@esbuild/android-arm": optional: true - bin: - jest: bin/jest.js - checksum: 10/6cc62b34d002c034203065a31e5e9a19e7c76d9e8ef447a6f70f759c0714cb212c6245f75e270ba458620f9c7b26063cd8cf6cd1f7e3afd659a7cc08add17307 - languageName: node - linkType: hard - -"jest-config@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-config@npm:29.7.0" - dependencies: - "@babel/core": "npm:^7.11.6" - "@jest/test-sequencer": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - babel-jest: "npm:^29.7.0" - chalk: "npm:^4.0.0" - ci-info: "npm:^3.2.0" - deepmerge: "npm:^4.2.2" - glob: "npm:^7.1.3" - graceful-fs: "npm:^4.2.9" - jest-circus: "npm:^29.7.0" - jest-environment-node: "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - jest-regex-util: "npm:^29.6.3" - jest-resolve: "npm:^29.7.0" - jest-runner: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - micromatch: "npm:^4.0.4" - parse-json: "npm:^5.2.0" - pretty-format: "npm:^29.7.0" - slash: "npm:^3.0.0" - strip-json-comments: "npm:^3.1.1" - peerDependencies: - "@types/node": "*" - ts-node: ">=9.0.0" - peerDependenciesMeta: - "@types/node": + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": optional: true - ts-node: + "@esbuild/linux-ppc64": optional: true - checksum: 10/6bdf570e9592e7d7dd5124fc0e21f5fe92bd15033513632431b211797e3ab57eaa312f83cc6481b3094b72324e369e876f163579d60016677c117ec4853cf02b + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10/227ffe9b31f0b184a0b0a0210bb9d32b2b115b8c5c9b09f08db2c3928cb470fc55a22dbba3c2894365d3abcc62c2089b85638be96a20691d1234d31990ea01b2 languageName: node linkType: hard -"jest-diff@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-diff@npm:29.7.0" +"estree-walker@npm:^3.0.3": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" dependencies: - chalk: "npm:^4.0.0" - diff-sequences: "npm:^29.6.3" - jest-get-type: "npm:^29.6.3" - pretty-format: "npm:^29.7.0" - checksum: 10/6f3a7eb9cd9de5ea9e5aa94aed535631fa6f80221832952839b3cb59dd419b91c20b73887deb0b62230d06d02d6b6cf34ebb810b88d904bb4fe1e2e4f0905c98 + "@types/estree": "npm:^1.0.0" + checksum: 10/a65728d5727b71de172c5df323385755a16c0fdab8234dc756c3854cfee343261ddfbb72a809a5660fac8c75d960bb3e21aa898c2d7e9b19bb298482ca58a3af languageName: node linkType: hard -"jest-docblock@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-docblock@npm:29.7.0" - dependencies: - detect-newline: "npm:^3.0.0" - checksum: 10/8d48818055bc96c9e4ec2e217a5a375623c0d0bfae8d22c26e011074940c202aa2534a3362294c81d981046885c05d304376afba9f2874143025981148f3e96d +"expect-type@npm:^1.2.1": + version: 1.2.1 + resolution: "expect-type@npm:1.2.1" + checksum: 10/d121d90f4f3f705ca0b656e36f28c0ba91483d0cddf2876e64e23c3dea2f2d5853e9c0c9a4e90eb4b3e4663bf09c2c02e9729c339dcd308c70b2107188e6b286 languageName: node linkType: hard -"jest-each@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-each@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - chalk: "npm:^4.0.0" - jest-get-type: "npm:^29.6.3" - jest-util: "npm:^29.7.0" - pretty-format: "npm:^29.7.0" - checksum: 10/bd1a077654bdaa013b590deb5f7e7ade68f2e3289180a8c8f53bc8a49f3b40740c0ec2d3a3c1aee906f682775be2bebbac37491d80b634d15276b0aa0f2e3fda +"exponential-backoff@npm:^3.1.1": + version: 3.1.2 + resolution: "exponential-backoff@npm:3.1.2" + checksum: 10/ca2f01f1aa4dafd3f3917bd531ab5be08c6f5f4b2389d2e974f903de3cbeb50b9633374353516b6afd70905775e33aba11afab1232d3acf0aa2963b98a611c51 languageName: node linkType: hard -"jest-environment-node@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-environment-node@npm:29.7.0" +"fast-check@npm:^3.15.0": + version: 3.23.2 + resolution: "fast-check@npm:3.23.2" dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/fake-timers": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - jest-mock: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - checksum: 10/9cf7045adf2307cc93aed2f8488942e39388bff47ec1df149a997c6f714bfc66b2056768973770d3f8b1bf47396c19aa564877eb10ec978b952c6018ed1bd637 + pure-rand: "npm:^6.1.0" + checksum: 10/dab344146b778e8bc2973366ea55528d1b58d3e3037270262b877c54241e800c4d744957722c24705c787020d702aece11e57c9e3dbd5ea19c3e10926bf1f3fe languageName: node linkType: hard -"jest-fast-check@npm:^2.0.0": - version: 2.0.0 - resolution: "jest-fast-check@npm:2.0.0" +"fdir@npm:^6.4.4": + version: 6.4.4 + resolution: "fdir@npm:6.4.4" peerDependencies: - fast-check: ^3.0.0 - jest: ">=25.1.0" - checksum: 10/70b68b673c04b638303061b72392522903523d1fdeb0c83683186d5611bab5bfe8156ae42b8a08f924a5219ca94f02fd2eb2034cd27a29fef25a3124e7ed4cc6 + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10/d0000d6b790059b35f4ed19acc8847a66452e0bc68b28766c929ffd523e5ec2083811fc8a545e4a1d4945ce70e887b3a610c145c681073b506143ae3076342ed languageName: node linkType: hard -"jest-get-type@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-get-type@npm:29.6.3" - checksum: 10/88ac9102d4679d768accae29f1e75f592b760b44277df288ad76ce5bf038c3f5ce3719dea8aa0f035dac30e9eb034b848ce716b9183ad7cc222d029f03e92205 +"fflate@npm:^0.8.2": + version: 0.8.2 + resolution: "fflate@npm:0.8.2" + checksum: 10/2bd26ba6d235d428de793c6a0cd1aaa96a06269ebd4e21b46c8fd1bd136abc631acf27e188d47c3936db090bf3e1ede11d15ce9eae9bffdc4bfe1b9dc66ca9cb languageName: node linkType: hard -"jest-haste-map@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-haste-map@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - "@types/graceful-fs": "npm:^4.1.3" - "@types/node": "npm:*" - anymatch: "npm:^3.0.3" - fb-watchman: "npm:^2.0.0" - fsevents: "npm:^2.3.2" - graceful-fs: "npm:^4.2.9" - jest-regex-util: "npm:^29.6.3" - jest-util: "npm:^29.7.0" - jest-worker: "npm:^29.7.0" - micromatch: "npm:^4.0.4" - walker: "npm:^1.0.8" - dependenciesMeta: - fsevents: - optional: true - checksum: 10/8531b42003581cb18a69a2774e68c456fb5a5c3280b1b9b77475af9e346b6a457250f9d756bfeeae2fe6cbc9ef28434c205edab9390ee970a919baddfa08bb85 +"flatted@npm:^3.3.3": + version: 3.3.3 + resolution: "flatted@npm:3.3.3" + checksum: 10/8c96c02fbeadcf4e8ffd0fa24983241e27698b0781295622591fc13585e2f226609d95e422bcf2ef044146ffacb6b68b1f20871454eddf75ab3caa6ee5f4a1fe languageName: node linkType: hard -"jest-leak-detector@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-leak-detector@npm:29.7.0" +"foreground-child@npm:^3.1.0": + version: 3.3.1 + resolution: "foreground-child@npm:3.3.1" dependencies: - jest-get-type: "npm:^29.6.3" - pretty-format: "npm:^29.7.0" - checksum: 10/e3950e3ddd71e1d0c22924c51a300a1c2db6cf69ec1e51f95ccf424bcc070f78664813bef7aed4b16b96dfbdeea53fe358f8aeaaea84346ae15c3735758f1605 + cross-spawn: "npm:^7.0.6" + signal-exit: "npm:^4.0.1" + checksum: 10/427b33f997a98073c0424e5c07169264a62cda806d8d2ded159b5b903fdfc8f0a1457e06b5fc35506497acb3f1e353f025edee796300209ac6231e80edece835 languageName: node linkType: hard -"jest-matcher-utils@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-matcher-utils@npm:29.7.0" +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" dependencies: - chalk: "npm:^4.0.0" - jest-diff: "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - pretty-format: "npm:^29.7.0" - checksum: 10/981904a494299cf1e3baed352f8a3bd8b50a8c13a662c509b6a53c31461f94ea3bfeffa9d5efcfeb248e384e318c87de7e3baa6af0f79674e987482aa189af40 + minipass: "npm:^7.0.3" + checksum: 10/af143246cf6884fe26fa281621d45cfe111d34b30535a475bfa38dafe343dadb466c047a924ffc7d6b7b18265df4110224ce3803806dbb07173bf2087b648d7f languageName: node linkType: hard -"jest-message-util@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-message-util@npm:29.7.0" - dependencies: - "@babel/code-frame": "npm:^7.12.13" - "@jest/types": "npm:^29.6.3" - "@types/stack-utils": "npm:^2.0.0" - chalk: "npm:^4.0.0" - graceful-fs: "npm:^4.2.9" - micromatch: "npm:^4.0.4" - pretty-format: "npm:^29.7.0" - slash: "npm:^3.0.0" - stack-utils: "npm:^2.0.3" - checksum: 10/31d53c6ed22095d86bab9d14c0fa70c4a92c749ea6ceece82cf30c22c9c0e26407acdfbdb0231435dc85a98d6d65ca0d9cbcd25cd1abb377fe945e843fb770b9 - languageName: node - linkType: hard - -"jest-mock@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-mock@npm:29.7.0" +"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" dependencies: - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - jest-util: "npm:^29.7.0" - checksum: 10/ae51d1b4f898724be5e0e52b2268a68fcd876d9b20633c864a6dd6b1994cbc48d62402b0f40f3a1b669b30ebd648821f086c26c08ffde192ced951ff4670d51c + node-gyp: "npm:latest" + checksum: 10/4c1ade961ded57cdbfbb5cac5106ec17bc8bccd62e16343c569a0ceeca83b9dfef87550b4dc5cbb89642da412b20c5071f304c8c464b80415446e8e155a038c0 + conditions: os=darwin languageName: node linkType: hard -"jest-pnp-resolver@npm:^1.2.2": - version: 1.2.3 - resolution: "jest-pnp-resolver@npm:1.2.3" - peerDependencies: - jest-resolve: "*" - peerDependenciesMeta: - jest-resolve: - optional: true - checksum: 10/db1a8ab2cb97ca19c01b1cfa9a9c8c69a143fde833c14df1fab0766f411b1148ff0df878adea09007ac6a2085ec116ba9a996a6ad104b1e58c20adbf88eed9b2 +"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin languageName: node linkType: hard -"jest-regex-util@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-regex-util@npm:29.6.3" - checksum: 10/0518beeb9bf1228261695e54f0feaad3606df26a19764bc19541e0fc6e2a3737191904607fb72f3f2ce85d9c16b28df79b7b1ec9443aa08c3ef0e9efda6f8f2a +"get-east-asian-width@npm:^1.0.0": + version: 1.3.0 + resolution: "get-east-asian-width@npm:1.3.0" + checksum: 10/8e8e779eb28701db7fdb1c8cab879e39e6ae23f52dadd89c8aed05869671cee611a65d4f8557b83e981428623247d8bc5d0c7a4ef3ea7a41d826e73600112ad8 languageName: node linkType: hard -"jest-resolve-dependencies@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-resolve-dependencies@npm:29.7.0" +"glob@npm:^10.2.2": + version: 10.4.5 + resolution: "glob@npm:10.4.5" dependencies: - jest-regex-util: "npm:^29.6.3" - jest-snapshot: "npm:^29.7.0" - checksum: 10/1e206f94a660d81e977bcfb1baae6450cb4a81c92e06fad376cc5ea16b8e8c6ea78c383f39e95591a9eb7f925b6a1021086c38941aa7c1b8a6a813c2f6e93675 + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^3.1.2" + minimatch: "npm:^9.0.4" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^1.11.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10/698dfe11828b7efd0514cd11e573eaed26b2dff611f0400907281ce3eab0c1e56143ef9b35adc7c77ecc71fba74717b510c7c223d34ca8a98ec81777b293d4ac languageName: node linkType: hard -"jest-resolve@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-resolve@npm:29.7.0" - dependencies: - chalk: "npm:^4.0.0" - graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.7.0" - jest-pnp-resolver: "npm:^1.2.2" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - resolve: "npm:^1.20.0" - resolve.exports: "npm:^2.0.0" - slash: "npm:^3.0.0" - checksum: 10/faa466fd9bc69ea6c37a545a7c6e808e073c66f46ab7d3d8a6ef084f8708f201b85d5fe1799789578b8b47fa1de47b9ee47b414d1863bc117a49e032ba77b7c7 - languageName: node - linkType: hard - -"jest-runner@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-runner@npm:29.7.0" - dependencies: - "@jest/console": "npm:^29.7.0" - "@jest/environment": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - chalk: "npm:^4.0.0" - emittery: "npm:^0.13.1" - graceful-fs: "npm:^4.2.9" - jest-docblock: "npm:^29.7.0" - jest-environment-node: "npm:^29.7.0" - jest-haste-map: "npm:^29.7.0" - jest-leak-detector: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-resolve: "npm:^29.7.0" - jest-runtime: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-watcher: "npm:^29.7.0" - jest-worker: "npm:^29.7.0" - p-limit: "npm:^3.1.0" - source-map-support: "npm:0.5.13" - checksum: 10/9d8748a494bd90f5c82acea99be9e99f21358263ce6feae44d3f1b0cd90991b5df5d18d607e73c07be95861ee86d1cbab2a3fc6ca4b21805f07ac29d47c1da1e - languageName: node - linkType: hard - -"jest-runtime@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-runtime@npm:29.7.0" - dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/fake-timers": "npm:^29.7.0" - "@jest/globals": "npm:^29.7.0" - "@jest/source-map": "npm:^29.6.3" - "@jest/test-result": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - chalk: "npm:^4.0.0" - cjs-module-lexer: "npm:^1.0.0" - collect-v8-coverage: "npm:^1.0.0" - glob: "npm:^7.1.3" - graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-mock: "npm:^29.7.0" - jest-regex-util: "npm:^29.6.3" - jest-resolve: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - slash: "npm:^3.0.0" - strip-bom: "npm:^4.0.0" - checksum: 10/59eb58eb7e150e0834a2d0c0d94f2a0b963ae7182cfa6c63f2b49b9c6ef794e5193ef1634e01db41420c36a94cefc512cdd67a055cd3e6fa2f41eaf0f82f5a20 - languageName: node - linkType: hard - -"jest-snapshot@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-snapshot@npm:29.7.0" - dependencies: - "@babel/core": "npm:^7.11.6" - "@babel/generator": "npm:^7.7.2" - "@babel/plugin-syntax-jsx": "npm:^7.7.2" - "@babel/plugin-syntax-typescript": "npm:^7.7.2" - "@babel/types": "npm:^7.3.3" - "@jest/expect-utils": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - babel-preset-current-node-syntax: "npm:^1.0.0" - chalk: "npm:^4.0.0" - expect: "npm:^29.7.0" - graceful-fs: "npm:^4.2.9" - jest-diff: "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - jest-matcher-utils: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - natural-compare: "npm:^1.4.0" - pretty-format: "npm:^29.7.0" - semver: "npm:^7.5.3" - checksum: 10/cb19a3948256de5f922d52f251821f99657339969bf86843bd26cf3332eae94883e8260e3d2fba46129a27c3971c1aa522490e460e16c7fad516e82d10bbf9f8 - languageName: node - linkType: hard - -"jest-util@npm:^29.0.0, jest-util@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-util@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - chalk: "npm:^4.0.0" - ci-info: "npm:^3.2.0" - graceful-fs: "npm:^4.2.9" - picomatch: "npm:^2.2.3" - checksum: 10/30d58af6967e7d42bd903ccc098f3b4d3859ed46238fbc88d4add6a3f10bea00c226b93660285f058bc7a65f6f9529cf4eb80f8d4707f79f9e3a23686b4ab8f3 +"graceful-fs@npm:^4.2.6": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 languageName: node linkType: hard -"jest-validate@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-validate@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - camelcase: "npm:^6.2.0" - chalk: "npm:^4.0.0" - jest-get-type: "npm:^29.6.3" - leven: "npm:^3.1.0" - pretty-format: "npm:^29.7.0" - checksum: 10/8ee1163666d8eaa16d90a989edba2b4a3c8ab0ffaa95ad91b08ca42b015bfb70e164b247a5b17f9de32d096987cada63ed8491ab82761bfb9a28bc34b27ae161 +"http-cache-semantics@npm:^4.1.1": + version: 4.2.0 + resolution: "http-cache-semantics@npm:4.2.0" + checksum: 10/4efd2dfcfeea9d5e88c84af450b9980be8a43c2c8179508b1c57c7b4421c855f3e8efe92fa53e0b3f4a43c85824ada930eabbc306d1b3beab750b6dcc5187693 languageName: node linkType: hard -"jest-watcher@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-watcher@npm:29.7.0" +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" dependencies: - "@jest/test-result": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - ansi-escapes: "npm:^4.2.1" - chalk: "npm:^4.0.0" - emittery: "npm:^0.13.1" - jest-util: "npm:^29.7.0" - string-length: "npm:^4.0.1" - checksum: 10/4f616e0345676631a7034b1d94971aaa719f0cd4a6041be2aa299be437ea047afd4fe05c48873b7963f5687a2f6c7cbf51244be8b14e313b97bfe32b1e127e55 + agent-base: "npm:^7.1.0" + debug: "npm:^4.3.4" + checksum: 10/d062acfa0cb82beeb558f1043c6ba770ea892b5fb7b28654dbc70ea2aeea55226dd34c02a294f6c1ca179a5aa483c4ea641846821b182edbd9cc5d89b54c6848 languageName: node linkType: hard -"jest-worker@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-worker@npm:29.7.0" +"https-proxy-agent@npm:^7.0.1": + version: 7.0.6 + resolution: "https-proxy-agent@npm:7.0.6" dependencies: - "@types/node": "npm:*" - jest-util: "npm:^29.7.0" - merge-stream: "npm:^2.0.0" - supports-color: "npm:^8.0.0" - checksum: 10/364cbaef00d8a2729fc760227ad34b5e60829e0869bd84976bdfbd8c0d0f9c2f22677b3e6dd8afa76ed174765351cd12bae3d4530c62eefb3791055127ca9745 + agent-base: "npm:^7.1.2" + debug: "npm:4" + checksum: 10/784b628cbd55b25542a9d85033bdfd03d4eda630fb8b3c9477959367f3be95dc476ed2ecbb9836c359c7c698027fc7b45723a302324433590f45d6c1706e8c13 languageName: node linkType: hard -"jest@npm:^29.7.0": - version: 29.7.0 - resolution: "jest@npm:29.7.0" +"iconv-lite@npm:^0.6.2": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" dependencies: - "@jest/core": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - import-local: "npm:^3.0.2" - jest-cli: "npm:^29.7.0" - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - bin: - jest: bin/jest.js - checksum: 10/97023d78446098c586faaa467fbf2c6b07ff06e2c85a19e3926adb5b0effe9ac60c4913ae03e2719f9c01ae8ffd8d92f6b262cedb9555ceeb5d19263d8c6362a + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10/24e3292dd3dadaa81d065c6f8c41b274a47098150d444b96e5f53b4638a9a71482921ea6a91a1f59bb71d9796de25e04afd05919fa64c360347ba65d3766f10f languageName: node linkType: hard -"js-tokens@npm:^4.0.0": - version: 4.0.0 - resolution: "js-tokens@npm:4.0.0" - checksum: 10/af37d0d913fb56aec6dc0074c163cc71cd23c0b8aad5c2350747b6721d37ba118af35abdd8b33c47ec2800de07dedb16a527ca9c530ee004093e04958bd0cbf2 +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 10/2d30b157a91fe1c1d7c6f653cbf263f039be6c5bfa959245a16d4ee191fc0f2af86c08545b6e6beeb041c56b574d2d5b9f95343d378ab49c0f37394d541e7fc8 languageName: node linkType: hard -"js-yaml@npm:^3.13.1": - version: 3.14.1 - resolution: "js-yaml@npm:3.14.1" +"ip-address@npm:^9.0.5": + version: 9.0.5 + resolution: "ip-address@npm:9.0.5" dependencies: - argparse: "npm:^1.0.7" - esprima: "npm:^4.0.0" - bin: - js-yaml: bin/js-yaml.js - checksum: 10/9e22d80b4d0105b9899135365f746d47466ed53ef4223c529b3c0f7a39907743fdbd3c4379f94f1106f02755b5e90b2faaf84801a891135544e1ea475d1a1379 - languageName: node - linkType: hard - -"jsbn@npm:1.1.0": - version: 1.1.0 - resolution: "jsbn@npm:1.1.0" - checksum: 10/bebe7ae829bbd586ce8cbe83501dd8cb8c282c8902a8aeeed0a073a89dc37e8103b1244f3c6acd60278bcbfe12d93a3f83c9ac396868a3b3bbc3c5e5e3b648ef + jsbn: "npm:1.1.0" + sprintf-js: "npm:^1.1.3" + checksum: 10/1ed81e06721af012306329b31f532b5e24e00cb537be18ddc905a84f19fe8f83a09a1699862bf3a1ec4b9dea93c55a3fa5faf8b5ea380431469df540f38b092c languageName: node linkType: hard -"jsesc@npm:^3.0.2": - version: 3.1.0 - resolution: "jsesc@npm:3.1.0" - bin: - jsesc: bin/jsesc - checksum: 10/20bd37a142eca5d1794f354db8f1c9aeb54d85e1f5c247b371de05d23a9751ecd7bd3a9c4fc5298ea6fa09a100dafb4190fa5c98c6610b75952c3487f3ce7967 +"is-fullwidth-code-point@npm:^3.0.0": + version: 3.0.0 + resolution: "is-fullwidth-code-point@npm:3.0.0" + checksum: 10/44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 languageName: node linkType: hard -"json-parse-even-better-errors@npm:^2.3.0": - version: 2.3.1 - resolution: "json-parse-even-better-errors@npm:2.3.1" - checksum: 10/5f3a99009ed5f2a5a67d06e2f298cc97bc86d462034173308156f15b43a6e850be8511dc204b9b94566305da2947f7d90289657237d210351a39059ff9d666cf +"is-interactive@npm:^2.0.0": + version: 2.0.0 + resolution: "is-interactive@npm:2.0.0" + checksum: 10/e8d52ad490bed7ae665032c7675ec07732bbfe25808b0efbc4d5a76b1a1f01c165f332775c63e25e9a03d319ebb6b24f571a9e902669fc1e40b0a60b5be6e26c languageName: node linkType: hard -"json5@npm:^2.2.3": - version: 2.2.3 - resolution: "json5@npm:2.2.3" - bin: - json5: lib/cli.js - checksum: 10/1db67b853ff0de3534085d630691d3247de53a2ed1390ba0ddff681ea43e9b3e30ecbdb65c5e9aab49435e44059c23dbd6fee8ee619419ba37465bb0dd7135da +"is-unicode-supported@npm:^1.3.0": + version: 1.3.0 + resolution: "is-unicode-supported@npm:1.3.0" + checksum: 10/20a1fc161afafaf49243551a5ac33b6c4cf0bbcce369fcd8f2951fbdd000c30698ce320de3ee6830497310a8f41880f8066d440aa3eb0a853e2aa4836dd89abc languageName: node linkType: hard -"kleur@npm:^3.0.3": - version: 3.0.3 - resolution: "kleur@npm:3.0.3" - checksum: 10/0c0ecaf00a5c6173d25059c7db2113850b5457016dfa1d0e3ef26da4704fbb186b4938d7611246d86f0ddf1bccf26828daa5877b1f232a65e7373d0122a83e7f +"is-unicode-supported@npm:^2.0.0": + version: 2.1.0 + resolution: "is-unicode-supported@npm:2.1.0" + checksum: 10/f254e3da6b0ab1a57a94f7273a7798dd35d1d45b227759f600d0fa9d5649f9c07fa8d3c8a6360b0e376adf916d151ec24fc9a50c5295c58bae7ca54a76a063f9 languageName: node linkType: hard -"leven@npm:^3.1.0": - version: 3.1.0 - resolution: "leven@npm:3.1.0" - checksum: 10/638401d534585261b6003db9d99afd244dfe82d75ddb6db5c0df412842d5ab30b2ef18de471aaec70fe69a46f17b4ae3c7f01d8a4e6580ef7adb9f4273ad1e55 +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 10/7c9f715c03aff08f35e98b1fadae1b9267b38f0615d501824f9743f3aab99ef10e303ce7db3f186763a0b70a19de5791ebfc854ff884d5a8c4d92211f642ec92 languageName: node linkType: hard -"lines-and-columns@npm:^1.1.6": - version: 1.2.4 - resolution: "lines-and-columns@npm:1.2.4" - checksum: 10/0c37f9f7fa212b38912b7145e1cd16a5f3cd34d782441c3e6ca653485d326f58b3caccda66efce1c5812bde4961bbde3374fae4b0d11bf1226152337f3894aa5 +"isexe@npm:^3.1.1": + version: 3.1.1 + resolution: "isexe@npm:3.1.1" + checksum: 10/7fe1931ee4e88eb5aa524cd3ceb8c882537bc3a81b02e438b240e47012eef49c86904d0f0e593ea7c3a9996d18d0f1f3be8d3eaa92333977b0c3a9d353d5563e languageName: node linkType: hard -"locate-path@npm:^5.0.0": - version: 5.0.0 - resolution: "locate-path@npm:5.0.0" +"jackspeak@npm:^3.1.2": + version: 3.4.3 + resolution: "jackspeak@npm:3.4.3" dependencies: - p-locate: "npm:^4.1.0" - checksum: 10/83e51725e67517287d73e1ded92b28602e3ae5580b301fe54bfb76c0c723e3f285b19252e375712316774cf52006cb236aed5704692c32db0d5d089b69696e30 + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 10/96f8786eaab98e4bf5b2a5d6d9588ea46c4d06bbc4f2eb861fdd7b6b182b16f71d8a70e79820f335d52653b16d4843b29dd9cdcf38ae80406756db9199497cf3 languageName: node linkType: hard -"lodash.memoize@npm:^4.1.2": - version: 4.1.2 - resolution: "lodash.memoize@npm:4.1.2" - checksum: 10/192b2168f310c86f303580b53acf81ab029761b9bd9caa9506a019ffea5f3363ea98d7e39e7e11e6b9917066c9d36a09a11f6fe16f812326390d8f3a54a1a6da +"jsbn@npm:1.1.0": + version: 1.1.0 + resolution: "jsbn@npm:1.1.0" + checksum: 10/bebe7ae829bbd586ce8cbe83501dd8cb8c282c8902a8aeeed0a073a89dc37e8103b1244f3c6acd60278bcbfe12d93a3f83c9ac396868a3b3bbc3c5e5e3b648ef languageName: node linkType: hard @@ -2806,6 +1371,13 @@ __metadata: languageName: node linkType: hard +"loupe@npm:^3.1.0, loupe@npm:^3.1.3": + version: 3.1.3 + resolution: "loupe@npm:3.1.3" + checksum: 10/9e98c34daf0eba48ccc603595e51f2ae002110982d84879cf78c51de2c632f0c571dfe82ce4210af60c32203d06b443465c269bda925076fe6d9b612cc65c321 + languageName: node + linkType: hard + "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" @@ -2813,25 +1385,16 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^5.1.1": - version: 5.1.1 - resolution: "lru-cache@npm:5.1.1" - dependencies: - yallist: "npm:^3.0.2" - checksum: 10/951d2673dcc64a7fb888bf3d13bc2fdf923faca97d89cdb405ba3dfff77e2b26e5798d405e78fcd7094c9e7b8b4dab2ddc5a4f8a11928af24a207b7c738ca3f8 - languageName: node - linkType: hard - -"make-dir@npm:^4.0.0": - version: 4.0.0 - resolution: "make-dir@npm:4.0.0" +"magic-string@npm:^0.30.17": + version: 0.30.17 + resolution: "magic-string@npm:0.30.17" dependencies: - semver: "npm:^7.5.3" - checksum: 10/bf0731a2dd3aab4db6f3de1585cea0b746bb73eb5a02e3d8d72757e376e64e6ada190b1eddcde5b2f24a81b688a9897efd5018737d05e02e2a671dda9cff8a8a + "@jridgewell/sourcemap-codec": "npm:^1.5.0" + checksum: 10/2f71af2b0afd78c2e9012a29b066d2c8ba45a9cd0c8070f7fd72de982fb1c403b4e3afdb1dae00691d56885ede66b772ef6bedf765e02e3a7066208fe2fec4aa languageName: node linkType: hard -"make-error@npm:^1.1.1, make-error@npm:^1.3.6": +"make-error@npm:^1.1.1": version: 1.3.6 resolution: "make-error@npm:1.3.6" checksum: 10/b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402 @@ -2857,39 +1420,6 @@ __metadata: languageName: node linkType: hard -"makeerror@npm:1.0.12": - version: 1.0.12 - resolution: "makeerror@npm:1.0.12" - dependencies: - tmpl: "npm:1.0.5" - checksum: 10/4c66ddfc654537333da952c084f507fa4c30c707b1635344eb35be894d797ba44c901a9cebe914aa29a7f61357543ba09b09dddbd7f65b4aee756b450f169f40 - languageName: node - linkType: hard - -"merge-stream@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-stream@npm:2.0.0" - checksum: 10/6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 - languageName: node - linkType: hard - -"micromatch@npm:^4.0.4": - version: 4.0.8 - resolution: "micromatch@npm:4.0.8" - dependencies: - braces: "npm:^3.0.3" - picomatch: "npm:^2.3.1" - checksum: 10/6bf2a01672e7965eb9941d1f02044fad2bd12486b5553dc1116ff24c09a8723157601dc992e74c911d896175918448762df3b3fd0a6b61037dd1a9766ddfbf58 - languageName: node - linkType: hard - -"mimic-fn@npm:^2.1.0": - version: 2.1.0 - resolution: "mimic-fn@npm:2.1.0" - checksum: 10/d2421a3444848ce7f84bd49115ddacff29c15745db73f54041edc906c14b131a38d05298dae3081667627a59b2eb1ca4b436ff2e1b80f69679522410418b478a - languageName: node - linkType: hard - "mimic-function@npm:^5.0.0": version: 5.0.1 resolution: "mimic-function@npm:5.0.1" @@ -2897,24 +1427,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: "npm:^1.1.7" - checksum: 10/e0b25b04cd4ec6732830344e5739b13f8690f8a012d73445a4a19fbc623f5dd481ef7a5827fde25954cd6026fede7574cc54dc4643c99d6c6b653d6203f94634 - languageName: node - linkType: hard - -"minimatch@npm:^5.0.1": - version: 5.1.6 - resolution: "minimatch@npm:5.1.6" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10/126b36485b821daf96d33b5c821dac600cc1ab36c87e7a532594f9b1652b1fa89a1eebcaad4dff17c764dce1a7ac1531327f190fed5f97d8f6e5f889c116c429 - languageName: node - linkType: hard - "minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -3009,6 +1521,13 @@ __metadata: languageName: node linkType: hard +"mrmime@npm:^2.0.0": + version: 2.0.1 + resolution: "mrmime@npm:2.0.1" + checksum: 10/1f966e2c05b7264209c4149ae50e8e830908eb64dd903535196f6ad72681fa109b794007288a3c2814f7a1ecf9ca192769909c0c374d974d604a8de5fc095d4a + languageName: node + linkType: hard + "ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" @@ -3016,10 +1535,12 @@ __metadata: languageName: node linkType: hard -"natural-compare@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare@npm:1.4.0" - checksum: 10/23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d +"nanoid@npm:^3.3.8": + version: 3.3.11 + resolution: "nanoid@npm:3.3.11" + bin: + nanoid: bin/nanoid.cjs + checksum: 10/73b5afe5975a307aaa3c95dfe3334c52cdf9ae71518176895229b8d65ab0d1c0417dd081426134eb7571c055720428ea5d57c645138161e7d10df80815527c48 languageName: node linkType: hard @@ -3050,20 +1571,6 @@ __metadata: languageName: node linkType: hard -"node-int64@npm:^0.4.0": - version: 0.4.0 - resolution: "node-int64@npm:0.4.0" - checksum: 10/b7afc2b65e56f7035b1a2eec57ae0fbdee7d742b1cdcd0f4387562b6527a011ab1cbe9f64cc8b3cca61e3297c9637c8bf61cec2e6b8d3a711d4b5267dfafbe02 - languageName: node - linkType: hard - -"node-releases@npm:^2.0.19": - version: 2.0.19 - resolution: "node-releases@npm:2.0.19" - checksum: 10/c2b33b4f0c40445aee56141f13ca692fa6805db88510e5bbb3baadb2da13e1293b738e638e15e4a8eb668bb9e97debb08e7a35409b477b5cc18f171d35a83045 - languageName: node - linkType: hard - "nopt@npm:^8.0.0": version: 8.1.0 resolution: "nopt@npm:8.1.0" @@ -3075,22 +1582,6 @@ __metadata: languageName: node linkType: hard -"normalize-path@npm:^3.0.0": - version: 3.0.0 - resolution: "normalize-path@npm:3.0.0" - checksum: 10/88eeb4da891e10b1318c4b2476b6e2ecbeb5ff97d946815ffea7794c31a89017c70d7f34b3c2ebf23ef4e9fc9fb99f7dffe36da22011b5b5c6ffa34f4873ec20 - languageName: node - linkType: hard - -"npm-run-path@npm:^4.0.1": - version: 4.0.1 - resolution: "npm-run-path@npm:4.0.1" - dependencies: - path-key: "npm:^3.0.0" - checksum: 10/5374c0cea4b0bbfdfae62da7bbdf1e1558d338335f4cacf2515c282ff358ff27b2ecb91ffa5330a8b14390ac66a1e146e10700440c1ab868208430f56b5f4d23 - languageName: node - linkType: hard - "object-inspect@npm:^1.12.3": version: 1.13.4 resolution: "object-inspect@npm:1.13.4" @@ -3098,24 +1589,6 @@ __metadata: languageName: node linkType: hard -"once@npm:^1.3.0": - version: 1.4.0 - resolution: "once@npm:1.4.0" - dependencies: - wrappy: "npm:1" - checksum: 10/cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 - languageName: node - linkType: hard - -"onetime@npm:^5.1.2": - version: 5.1.2 - resolution: "onetime@npm:5.1.2" - dependencies: - mimic-fn: "npm:^2.1.0" - checksum: 10/e9fd0695a01cf226652f0385bf16b7a24153dbbb2039f764c8ba6d2306a8506b0e4ce570de6ad99c7a6eb49520743afdb66edd95ee979c1a342554ed49a9aadd - languageName: node - linkType: hard - "onetime@npm:^7.0.0": version: 7.0.0 resolution: "onetime@npm:7.0.0" @@ -3142,33 +1615,6 @@ __metadata: languageName: node linkType: hard -"p-limit@npm:^2.2.0": - version: 2.3.0 - resolution: "p-limit@npm:2.3.0" - dependencies: - p-try: "npm:^2.0.0" - checksum: 10/84ff17f1a38126c3314e91ecfe56aecbf36430940e2873dadaa773ffe072dc23b7af8e46d4b6485d302a11673fe94c6b67ca2cfbb60c989848b02100d0594ac1 - languageName: node - linkType: hard - -"p-limit@npm:^3.1.0": - version: 3.1.0 - resolution: "p-limit@npm:3.1.0" - dependencies: - yocto-queue: "npm:^0.1.0" - checksum: 10/7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360 - languageName: node - linkType: hard - -"p-locate@npm:^4.1.0": - version: 4.1.0 - resolution: "p-locate@npm:4.1.0" - dependencies: - p-limit: "npm:^2.2.0" - checksum: 10/513bd14a455f5da4ebfcb819ef706c54adb09097703de6aeaa5d26fe5ea16df92b48d1ac45e01e3944ce1e6aa2a66f7f8894742b8c9d6e276e16cd2049a2b870 - languageName: node - linkType: hard - "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" @@ -3176,60 +1622,20 @@ __metadata: languageName: node linkType: hard -"p-try@npm:^2.0.0": - version: 2.2.0 - resolution: "p-try@npm:2.2.0" - checksum: 10/f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae - languageName: node - linkType: hard - "package-json-from-dist@npm:^1.0.0": version: 1.0.1 - resolution: "package-json-from-dist@npm:1.0.1" - checksum: 10/58ee9538f2f762988433da00e26acc788036914d57c71c246bf0be1b60cdbd77dd60b6a3e1a30465f0b248aeb80079e0b34cb6050b1dfa18c06953bb1cbc7602 - languageName: node - linkType: hard - -"parse-json@npm:^5.2.0": - version: 5.2.0 - resolution: "parse-json@npm:5.2.0" - dependencies: - "@babel/code-frame": "npm:^7.0.0" - error-ex: "npm:^1.3.1" - json-parse-even-better-errors: "npm:^2.3.0" - lines-and-columns: "npm:^1.1.6" - checksum: 10/62085b17d64da57f40f6afc2ac1f4d95def18c4323577e1eced571db75d9ab59b297d1d10582920f84b15985cbfc6b6d450ccbf317644cfa176f3ed982ad87e2 - languageName: node - linkType: hard - -"path-exists@npm:^4.0.0": - version: 4.0.0 - resolution: "path-exists@npm:4.0.0" - checksum: 10/505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 - languageName: node - linkType: hard - -"path-is-absolute@npm:^1.0.0": - version: 1.0.1 - resolution: "path-is-absolute@npm:1.0.1" - checksum: 10/060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 + resolution: "package-json-from-dist@npm:1.0.1" + checksum: 10/58ee9538f2f762988433da00e26acc788036914d57c71c246bf0be1b60cdbd77dd60b6a3e1a30465f0b248aeb80079e0b34cb6050b1dfa18c06953bb1cbc7602 languageName: node linkType: hard -"path-key@npm:^3.0.0, path-key@npm:^3.1.0": +"path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" checksum: 10/55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 languageName: node linkType: hard -"path-parse@npm:^1.0.7": - version: 1.0.7 - resolution: "path-parse@npm:1.0.7" - checksum: 10/49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a - languageName: node - linkType: hard - "path-scurry@npm:^1.11.1": version: 1.11.1 resolution: "path-scurry@npm:1.11.1" @@ -3240,17 +1646,24 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": - version: 1.1.1 - resolution: "picocolors@npm:1.1.1" - checksum: 10/e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 +"pathe@npm:^2.0.3": + version: 2.0.3 + resolution: "pathe@npm:2.0.3" + checksum: 10/01e9a69928f39087d96e1751ce7d6d50da8c39abf9a12e0ac2389c42c83bc76f78c45a475bd9026a02e6a6f79be63acc75667df855862fe567d99a00a540d23d + languageName: node + linkType: hard + +"pathval@npm:^2.0.0": + version: 2.0.0 + resolution: "pathval@npm:2.0.0" + checksum: 10/b91575bf9cdf01757afd7b5e521eb8a0b874a49bc972d08e0047cfea0cd3c019f5614521d4bc83d2855e3fcc331db6817dfd533dd8f3d90b16bc76fad2450fc1 languageName: node linkType: hard -"picomatch@npm:^2.0.4, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": - version: 2.3.1 - resolution: "picomatch@npm:2.3.1" - checksum: 10/60c2595003b05e4535394d1da94850f5372c9427ca4413b71210f437f7b2ca091dbd611c45e8b37d10036fa8eade25c1b8951654f9d3973bfa66a2ff4d3b08bc +"picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10/e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 languageName: node linkType: hard @@ -3261,30 +1674,14 @@ __metadata: languageName: node linkType: hard -"pirates@npm:^4.0.4": - version: 4.0.7 - resolution: "pirates@npm:4.0.7" - checksum: 10/2427f371366081ae42feb58214f04805d6b41d6b84d74480ebcc9e0ddbd7105a139f7c653daeaf83ad8a1a77214cf07f64178e76de048128fec501eab3305a96 - languageName: node - linkType: hard - -"pkg-dir@npm:^4.2.0": - version: 4.2.0 - resolution: "pkg-dir@npm:4.2.0" - dependencies: - find-up: "npm:^4.0.0" - checksum: 10/9863e3f35132bf99ae1636d31ff1e1e3501251d480336edb1c211133c8d58906bed80f154a1d723652df1fda91e01c7442c2eeaf9dc83157c7ae89087e43c8d6 - languageName: node - linkType: hard - -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": - version: 29.7.0 - resolution: "pretty-format@npm:29.7.0" +"postcss@npm:^8.5.3": + version: 8.5.3 + resolution: "postcss@npm:8.5.3" dependencies: - "@jest/schemas": "npm:^29.6.3" - ansi-styles: "npm:^5.0.0" - react-is: "npm:^18.0.0" - checksum: 10/dea96bc83c83cd91b2bfc55757b6b2747edcaac45b568e46de29deee80742f17bc76fe8898135a70d904f4928eafd8bb693cd1da4896e8bdd3c5e82cadf1d2bb + nanoid: "npm:^3.3.8" + picocolors: "npm:^1.1.1" + source-map-js: "npm:^1.2.1" + checksum: 10/6d7e21a772e8b05bf102636918654dac097bac013f0dc8346b72ac3604fc16829646f94ea862acccd8f82e910b00e2c11c1f0ea276543565d278c7ca35516a7c languageName: node linkType: hard @@ -3305,86 +1702,13 @@ __metadata: languageName: node linkType: hard -"prompts@npm:^2.0.1": - version: 2.4.2 - resolution: "prompts@npm:2.4.2" - dependencies: - kleur: "npm:^3.0.3" - sisteransi: "npm:^1.0.5" - checksum: 10/c52536521a4d21eff4f2f2aa4572446cad227464066365a7167e52ccf8d9839c099f9afec1aba0eed3d5a2514b3e79e0b3e7a1dc326b9acde6b75d27ed74b1a9 - languageName: node - linkType: hard - -"pure-rand@npm:^6.0.0, pure-rand@npm:^6.1.0": +"pure-rand@npm:^6.1.0": version: 6.1.0 resolution: "pure-rand@npm:6.1.0" checksum: 10/256aa4bcaf9297256f552914e03cbdb0039c8fe1db11fa1e6d3f80790e16e563eb0a859a1e61082a95e224fc0c608661839439f8ecc6a3db4e48d46d99216ee4 languageName: node linkType: hard -"react-is@npm:^18.0.0": - version: 18.3.1 - resolution: "react-is@npm:18.3.1" - checksum: 10/d5f60c87d285af24b1e1e7eaeb123ec256c3c8bdea7061ab3932e3e14685708221bf234ec50b21e10dd07f008f1b966a2730a0ce4ff67905b3872ff2042aec22 - languageName: node - linkType: hard - -"require-directory@npm:^2.1.1": - version: 2.1.1 - resolution: "require-directory@npm:2.1.1" - checksum: 10/a72468e2589270d91f06c7d36ec97a88db53ae5d6fe3787fadc943f0b0276b10347f89b363b2a82285f650bdcc135ad4a257c61bdd4d00d6df1fa24875b0ddaf - languageName: node - linkType: hard - -"resolve-cwd@npm:^3.0.0": - version: 3.0.0 - resolution: "resolve-cwd@npm:3.0.0" - dependencies: - resolve-from: "npm:^5.0.0" - checksum: 10/546e0816012d65778e580ad62b29e975a642989108d9a3c5beabfb2304192fa3c9f9146fbdfe213563c6ff51975ae41bac1d3c6e047dd9572c94863a057b4d81 - languageName: node - linkType: hard - -"resolve-from@npm:^5.0.0": - version: 5.0.0 - resolution: "resolve-from@npm:5.0.0" - checksum: 10/be18a5e4d76dd711778664829841cde690971d02b6cbae277735a09c1c28f407b99ef6ef3cd585a1e6546d4097b28df40ed32c4a287b9699dcf6d7f208495e23 - languageName: node - linkType: hard - -"resolve.exports@npm:^2.0.0": - version: 2.0.3 - resolution: "resolve.exports@npm:2.0.3" - checksum: 10/536efee0f30a10fac8604e6cdc7844dbc3f4313568d09f06db4f7ed8a5b8aeb8585966fe975083d1f2dfbc87cf5f8bc7ab65a5c23385c14acbb535ca79f8398a - languageName: node - linkType: hard - -"resolve@npm:^1.20.0": - version: 1.22.10 - resolution: "resolve@npm:1.22.10" - dependencies: - is-core-module: "npm:^2.16.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10/0a398b44da5c05e6e421d70108822c327675febb880eebe905587628de401854c61d5df02866ff34fc4cb1173a51c9f0e84a94702738df3611a62e2acdc68181 - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A^1.20.0#optional!builtin": - version: 1.22.10 - resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.16.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10/d4d878bfe3702d215ea23e75e0e9caf99468e3db76f5ca100d27ebdc527366fee3877e54bce7d47cc72ca8952fc2782a070d238bfa79a550eeb0082384c3b81a - languageName: node - linkType: hard - "restore-cursor@npm:^5.0.0": version: 5.1.0 resolution: "restore-cursor@npm:5.1.0" @@ -3402,23 +1726,96 @@ __metadata: languageName: node linkType: hard +"rollup@npm:^4.34.9": + version: 4.40.2 + resolution: "rollup@npm:4.40.2" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.40.2" + "@rollup/rollup-android-arm64": "npm:4.40.2" + "@rollup/rollup-darwin-arm64": "npm:4.40.2" + "@rollup/rollup-darwin-x64": "npm:4.40.2" + "@rollup/rollup-freebsd-arm64": "npm:4.40.2" + "@rollup/rollup-freebsd-x64": "npm:4.40.2" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.40.2" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.40.2" + "@rollup/rollup-linux-arm64-gnu": "npm:4.40.2" + "@rollup/rollup-linux-arm64-musl": "npm:4.40.2" + "@rollup/rollup-linux-loongarch64-gnu": "npm:4.40.2" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.40.2" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.40.2" + "@rollup/rollup-linux-riscv64-musl": "npm:4.40.2" + "@rollup/rollup-linux-s390x-gnu": "npm:4.40.2" + "@rollup/rollup-linux-x64-gnu": "npm:4.40.2" + "@rollup/rollup-linux-x64-musl": "npm:4.40.2" + "@rollup/rollup-win32-arm64-msvc": "npm:4.40.2" + "@rollup/rollup-win32-ia32-msvc": "npm:4.40.2" + "@rollup/rollup-win32-x64-msvc": "npm:4.40.2" + "@types/estree": "npm:1.0.7" + fsevents: "npm:~2.3.2" + dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-freebsd-arm64": + optional: true + "@rollup/rollup-freebsd-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-loongarch64-gnu": + optional: true + "@rollup/rollup-linux-powerpc64le-gnu": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-riscv64-musl": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10/ab767c56e37410257864e051fccbdaf448ac7774129bf39295de716af816c49e0247e72749959969efbd892fc64e096880fa269764adf765579100e81abf5e7c + languageName: node + linkType: hard + "root-workspace-0b6124@workspace:.": version: 0.0.0-use.local resolution: "root-workspace-0b6124@workspace:." dependencies: "@biomejs/biome": "npm:1.9.4" - "@midnight-ntwrk/compact-runtime": "npm:^0.7.0" - "@midnight-ntwrk/ledger": "npm:^3.0.6" - "@midnight-ntwrk/zswap": "npm:^3.0.6" - "@types/jest": "npm:^29.5.6" + "@midnight-ntwrk/compact-runtime": "npm:^0.8.0" + "@midnight-ntwrk/ledger": "npm:^4.0.0" + "@midnight-ntwrk/zswap": "npm:^4.0.0" "@types/node": "npm:^18.18.6" + "@vitest/ui": "npm:^3.1.3" fast-check: "npm:^3.15.0" - jest: "npm:^29.7.0" - jest-fast-check: "npm:^2.0.0" - ts-jest: "npm:^29.1.1" - ts-node: "npm:^10.9.1" + ts-node: "npm:^10.9.2" turbo: "npm:^2.5.1" typescript: "npm:^5.2.2" + vitest: "npm:^3.1.3" languageName: unknown linkType: soft @@ -3429,21 +1826,12 @@ __metadata: languageName: node linkType: hard -"semver@npm:^6.3.0, semver@npm:^6.3.1": - version: 6.3.1 - resolution: "semver@npm:6.3.1" - bin: - semver: bin/semver.js - checksum: 10/1ef3a85bd02a760c6ef76a45b8c1ce18226de40831e02a00bad78485390b98b6ccaa31046245fc63bba4a47a6a592b6c7eedc65cc47126e60489f9cc1ce3ed7e - languageName: node - linkType: hard - -"semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.7.1": - version: 7.7.1 - resolution: "semver@npm:7.7.1" +"semver@npm:^7.3.5": + version: 7.7.2 + resolution: "semver@npm:7.7.2" bin: semver: bin/semver.js - checksum: 10/4cfa1eb91ef3751e20fc52e47a935a0118d56d6f15a837ab814da0c150778ba2ca4f1a4d9068b33070ea4273629e615066664c2cfcd7c272caf7a8a0f6518b2c + checksum: 10/7a24cffcaa13f53c09ce55e05efe25cd41328730b2308678624f8b9f5fc3093fc4d189f47950f0b811ff8f3c3039c24a2c36717ba7961615c682045bf03e1dda languageName: node linkType: hard @@ -3463,10 +1851,10 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: 10/a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 +"siginfo@npm:^2.0.0": + version: 2.0.0 + resolution: "siginfo@npm:2.0.0" + checksum: 10/e93ff66c6531a079af8fb217240df01f980155b5dc408d2d7bebc398dd284e383eb318153bf8acd4db3c4fe799aa5b9a641e38b0ba3b1975700b1c89547ea4e7 languageName: node linkType: hard @@ -3477,17 +1865,14 @@ __metadata: languageName: node linkType: hard -"sisteransi@npm:^1.0.5": - version: 1.0.5 - resolution: "sisteransi@npm:1.0.5" - checksum: 10/aba6438f46d2bfcef94cf112c835ab395172c75f67453fe05c340c770d3c402363018ae1ab4172a1026a90c47eaccf3af7b6ff6fa749a680c2929bd7fa2b37a4 - languageName: node - linkType: hard - -"slash@npm:^3.0.0": - version: 3.0.0 - resolution: "slash@npm:3.0.0" - checksum: 10/94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c +"sirv@npm:^3.0.1": + version: 3.0.1 + resolution: "sirv@npm:3.0.1" + dependencies: + "@polka/url": "npm:^1.0.0-next.24" + mrmime: "npm:^2.0.0" + totalist: "npm:^3.0.0" + checksum: 10/b110ebe28eb1740772fbbfacb6c71c58d1ec8ec17a5ae2852a5418c3ef41d52d473663613de808f8a6337ec29dd446414d0d059e75bfd13fb9630d18651c99f2 languageName: node linkType: hard @@ -3519,20 +1904,10 @@ __metadata: languageName: node linkType: hard -"source-map-support@npm:0.5.13": - version: 0.5.13 - resolution: "source-map-support@npm:0.5.13" - dependencies: - buffer-from: "npm:^1.0.0" - source-map: "npm:^0.6.0" - checksum: 10/d1514a922ac9c7e4786037eeff6c3322f461cd25da34bb9fefb15387b3490531774e6e31d95ab6d5b84a3e139af9c3a570ccaee6b47bd7ea262691ed3a8bc34e - languageName: node - linkType: hard - -"source-map@npm:^0.6.0, source-map@npm:^0.6.1": - version: 0.6.1 - resolution: "source-map@npm:0.6.1" - checksum: 10/59ef7462f1c29d502b3057e822cdbdae0b0e565302c4dd1a95e11e793d8d9d62006cdc10e0fd99163ca33ff2071360cf50ee13f90440806e7ed57d81cba2f7ff +"source-map-js@npm:^1.2.1": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 10/ff9d8c8bf096d534a5b7707e0382ef827b4dd360a577d3f34d2b9f48e12c9d230b5747974ee7c607f0df65113732711bb701fe9ece3c7edbd43cb2294d707df3 languageName: node linkType: hard @@ -3543,13 +1918,6 @@ __metadata: languageName: node linkType: hard -"sprintf-js@npm:~1.0.2": - version: 1.0.3 - resolution: "sprintf-js@npm:1.0.3" - checksum: 10/c34828732ab8509c2741e5fd1af6b767c3daf2c642f267788f933a65b1614943c282e74c4284f4fa749c264b18ee016a0d37a3e5b73aee446da46277d3a85daa - languageName: node - linkType: hard - "ssri@npm:^12.0.0": version: 12.0.0 resolution: "ssri@npm:12.0.0" @@ -3559,12 +1927,17 @@ __metadata: languageName: node linkType: hard -"stack-utils@npm:^2.0.3": - version: 2.0.6 - resolution: "stack-utils@npm:2.0.6" - dependencies: - escape-string-regexp: "npm:^2.0.0" - checksum: 10/cdc988acbc99075b4b036ac6014e5f1e9afa7e564482b687da6384eee6a1909d7eaffde85b0a17ffbe186c5247faf6c2b7544e802109f63b72c7be69b13151bb +"stackback@npm:0.0.2": + version: 0.0.2 + resolution: "stackback@npm:0.0.2" + checksum: 10/2d4dc4e64e2db796de4a3c856d5943daccdfa3dd092e452a1ce059c81e9a9c29e0b9badba91b43ef0d5ff5c04ee62feb3bcc559a804e16faf447bac2d883aa99 + languageName: node + linkType: hard + +"std-env@npm:^3.9.0": + version: 3.9.0 + resolution: "std-env@npm:3.9.0" + checksum: 10/3044b2c54a74be4f460db56725571241ab3ac89a91f39c7709519bc90fa37148784bc4cd7d3a301aa735f43bd174496f263563f76703ce3e81370466ab7c235b languageName: node linkType: hard @@ -3575,17 +1948,7 @@ __metadata: languageName: node linkType: hard -"string-length@npm:^4.0.1": - version: 4.0.2 - resolution: "string-length@npm:4.0.2" - dependencies: - char-regex: "npm:^1.0.2" - strip-ansi: "npm:^6.0.0" - checksum: 10/ce85533ef5113fcb7e522bcf9e62cb33871aa99b3729cec5595f4447f660b0cefd542ca6df4150c97a677d58b0cb727a3fe09ac1de94071d05526c73579bf505 - languageName: node - linkType: hard - -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -3636,52 +1999,6 @@ __metadata: languageName: node linkType: hard -"strip-bom@npm:^4.0.0": - version: 4.0.0 - resolution: "strip-bom@npm:4.0.0" - checksum: 10/9dbcfbaf503c57c06af15fe2c8176fb1bf3af5ff65003851a102749f875a6dbe0ab3b30115eccf6e805e9d756830d3e40ec508b62b3f1ddf3761a20ebe29d3f3 - languageName: node - linkType: hard - -"strip-final-newline@npm:^2.0.0": - version: 2.0.0 - resolution: "strip-final-newline@npm:2.0.0" - checksum: 10/69412b5e25731e1938184b5d489c32e340605bb611d6140344abc3421b7f3c6f9984b21dff296dfcf056681b82caa3bb4cc996a965ce37bcfad663e92eae9c64 - languageName: node - linkType: hard - -"strip-json-comments@npm:^3.1.1": - version: 3.1.1 - resolution: "strip-json-comments@npm:3.1.1" - checksum: 10/492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 - languageName: node - linkType: hard - -"supports-color@npm:^7.1.0": - version: 7.2.0 - resolution: "supports-color@npm:7.2.0" - dependencies: - has-flag: "npm:^4.0.0" - checksum: 10/c8bb7afd564e3b26b50ca6ee47572c217526a1389fe018d00345856d4a9b08ffbd61fadaf283a87368d94c3dcdb8f5ffe2650a5a65863e21ad2730ca0f05210a - languageName: node - linkType: hard - -"supports-color@npm:^8.0.0": - version: 8.1.1 - resolution: "supports-color@npm:8.1.1" - dependencies: - has-flag: "npm:^4.0.0" - checksum: 10/157b534df88e39c5518c5e78c35580c1eca848d7dbaf31bbe06cdfc048e22c7ff1a9d046ae17b25691128f631a51d9ec373c1b740c12ae4f0de6e292037e4282 - languageName: node - linkType: hard - -"supports-preserve-symlinks-flag@npm:^1.0.0": - version: 1.0.0 - resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 10/a9dc19ae2220c952bd2231d08ddeecb1b0328b61e72071ff4000c8384e145cc07c1c0bdb3b5a1cb06e186a7b2790f1dee793418b332f6ddf320de25d9125be7e - languageName: node - linkType: hard - "tar@npm:^7.4.3": version: 7.4.3 resolution: "tar@npm:7.4.3" @@ -3696,18 +2013,21 @@ __metadata: languageName: node linkType: hard -"test-exclude@npm:^6.0.0": - version: 6.0.0 - resolution: "test-exclude@npm:6.0.0" - dependencies: - "@istanbuljs/schema": "npm:^0.1.2" - glob: "npm:^7.1.4" - minimatch: "npm:^3.0.4" - checksum: 10/8fccb2cb6c8fcb6bb4115394feb833f8b6cf4b9503ec2485c2c90febf435cac62abe882a0c5c51a37b9bbe70640cdd05acf5f45e486ac4583389f4b0855f69e5 +"tinybench@npm:^2.9.0": + version: 2.9.0 + resolution: "tinybench@npm:2.9.0" + checksum: 10/cfa1e1418e91289219501703c4693c70708c91ffb7f040fd318d24aef419fb5a43e0c0160df9471499191968b2451d8da7f8087b08c3133c251c40d24aced06c + languageName: node + linkType: hard + +"tinyexec@npm:^0.3.2": + version: 0.3.2 + resolution: "tinyexec@npm:0.3.2" + checksum: 10/b9d5fed3166fb1acd1e7f9a89afcd97ccbe18b9c1af0278e429455f6976d69271ba2d21797e7c36d57d6b05025e525d2882d88c2ab435b60d1ddf2fea361de57 languageName: node linkType: hard -"tinyglobby@npm:^0.2.12": +"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.13": version: 0.2.13 resolution: "tinyglobby@npm:0.2.13" dependencies: @@ -3717,61 +2037,35 @@ __metadata: languageName: node linkType: hard -"tmpl@npm:1.0.5": - version: 1.0.5 - resolution: "tmpl@npm:1.0.5" - checksum: 10/cd922d9b853c00fe414c5a774817be65b058d54a2d01ebb415840960406c669a0fc632f66df885e24cb022ec812739199ccbdb8d1164c3e513f85bfca5ab2873 +"tinypool@npm:^1.0.2": + version: 1.0.2 + resolution: "tinypool@npm:1.0.2" + checksum: 10/6109322f14b3763f65c8fa49fddab72cd3edd96b82dd50e05e63de74867329ff5353bff4377281ec963213d9314f37f4a353e9ee34bbac85fd4c1e4a568d6076 languageName: node linkType: hard -"to-regex-range@npm:^5.0.1": - version: 5.0.1 - resolution: "to-regex-range@npm:5.0.1" - dependencies: - is-number: "npm:^7.0.0" - checksum: 10/10dda13571e1f5ad37546827e9b6d4252d2e0bc176c24a101252153ef435d83696e2557fe128c4678e4e78f5f01e83711c703eef9814eb12dab028580d45980a +"tinyrainbow@npm:^2.0.0": + version: 2.0.0 + resolution: "tinyrainbow@npm:2.0.0" + checksum: 10/94d4e16246972614a5601eeb169ba94f1d49752426312d3cf8cc4f2cc663a2e354ffc653aa4de4eebccbf9eeebdd0caef52d1150271fdfde65d7ae7f3dcb9eb5 languageName: node linkType: hard -"ts-jest@npm:^29.1.1": - version: 29.3.2 - resolution: "ts-jest@npm:29.3.2" - dependencies: - bs-logger: "npm:^0.2.6" - ejs: "npm:^3.1.10" - fast-json-stable-stringify: "npm:^2.1.0" - jest-util: "npm:^29.0.0" - json5: "npm:^2.2.3" - lodash.memoize: "npm:^4.1.2" - make-error: "npm:^1.3.6" - semver: "npm:^7.7.1" - type-fest: "npm:^4.39.1" - yargs-parser: "npm:^21.1.1" - peerDependencies: - "@babel/core": ">=7.0.0-beta.0 <8" - "@jest/transform": ^29.0.0 - "@jest/types": ^29.0.0 - babel-jest: ^29.0.0 - jest: ^29.0.0 - typescript: ">=4.3 <6" - peerDependenciesMeta: - "@babel/core": - optional: true - "@jest/transform": - optional: true - "@jest/types": - optional: true - babel-jest: - optional: true - esbuild: - optional: true - bin: - ts-jest: cli.js - checksum: 10/62fb226a4df408174a3f28919c89440b2f5df4dec404bb49696591e61d75536b1c3be8ae726d187958a467654d82294d81d2dd70d9ec370542a30907183aaf61 +"tinyspy@npm:^3.0.2": + version: 3.0.2 + resolution: "tinyspy@npm:3.0.2" + checksum: 10/5db671b2ff5cd309de650c8c4761ca945459d7204afb1776db9a04fb4efa28a75f08517a8620c01ee32a577748802231ad92f7d5b194dc003ee7f987a2a06337 + languageName: node + linkType: hard + +"totalist@npm:^3.0.0": + version: 3.0.1 + resolution: "totalist@npm:3.0.1" + checksum: 10/5132d562cf88ff93fd710770a92f31dbe67cc19b5c6ccae2efc0da327f0954d211bbfd9456389655d726c624f284b4a23112f56d1da931ca7cfabbe1f45e778a languageName: node linkType: hard -"ts-node@npm:^10.9.1": +"ts-node@npm:^10.9.2": version: 10.9.2 resolution: "ts-node@npm:10.9.2" dependencies: @@ -3880,27 +2174,6 @@ __metadata: languageName: node linkType: hard -"type-detect@npm:4.0.8": - version: 4.0.8 - resolution: "type-detect@npm:4.0.8" - checksum: 10/5179e3b8ebc51fce1b13efb75fdea4595484433f9683bbc2dca6d99789dba4e602ab7922d2656f2ce8383987467f7770131d4a7f06a26287db0615d2f4c4ce7d - languageName: node - linkType: hard - -"type-fest@npm:^0.21.3": - version: 0.21.3 - resolution: "type-fest@npm:0.21.3" - checksum: 10/f4254070d9c3d83a6e573bcb95173008d73474ceadbbf620dd32d273940ca18734dff39c2b2480282df9afe5d1675ebed5499a00d791758748ea81f61a38961f - languageName: node - linkType: hard - -"type-fest@npm:^4.39.1": - version: 4.40.1 - resolution: "type-fest@npm:4.40.1" - checksum: 10/907767cd7889c8f17d94f4a811ec27c33339a9134f6842a1a56b4d6ee87cb1d6b01332f366a3f03adc10923fd6d511d73b73076f7ab5256bf5c0b43a03ab6e8b - languageName: node - linkType: hard - "typescript@npm:^5.2.2, typescript@npm:^5.8.2": version: 5.8.3 resolution: "typescript@npm:5.8.3" @@ -3953,20 +2226,6 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.1.1": - version: 1.1.3 - resolution: "update-browserslist-db@npm:1.1.3" - dependencies: - escalade: "npm:^3.2.0" - picocolors: "npm:^1.1.1" - peerDependencies: - browserslist: ">= 4.21.0" - bin: - update-browserslist-db: cli.js - checksum: 10/87af2776054ffb9194cf95e0201547d041f72ee44ce54b144da110e65ea7ca01379367407ba21de5c9edd52c74d95395366790de67f3eb4cc4afa0fe4424e76f - languageName: node - linkType: hard - "v8-compile-cache-lib@npm:^3.0.1": version: 3.0.1 resolution: "v8-compile-cache-lib@npm:3.0.1" @@ -3974,23 +2233,127 @@ __metadata: languageName: node linkType: hard -"v8-to-istanbul@npm:^9.0.1": - version: 9.3.0 - resolution: "v8-to-istanbul@npm:9.3.0" +"vite-node@npm:3.1.3": + version: 3.1.3 + resolution: "vite-node@npm:3.1.3" dependencies: - "@jridgewell/trace-mapping": "npm:^0.3.12" - "@types/istanbul-lib-coverage": "npm:^2.0.1" - convert-source-map: "npm:^2.0.0" - checksum: 10/fb1d70f1176cb9dc46cabbb3fd5c52c8f3e8738b61877b6e7266029aed0870b04140e3f9f4550ac32aebcfe1d0f38b0bac57e1e8fb97d68fec82f2b416148166 + cac: "npm:^6.7.14" + debug: "npm:^4.4.0" + es-module-lexer: "npm:^1.7.0" + pathe: "npm:^2.0.3" + vite: "npm:^5.0.0 || ^6.0.0" + bin: + vite-node: vite-node.mjs + checksum: 10/59c1e1397b055861390cf4e540ba1e968e4ad140df8e214f797dd73b9130f00855712779d4f6f0c8c5149bfe95db20ad55f349dd1962a143117a0d71d956235f languageName: node linkType: hard -"walker@npm:^1.0.8": - version: 1.0.8 - resolution: "walker@npm:1.0.8" +"vite@npm:^5.0.0 || ^6.0.0": + version: 6.3.5 + resolution: "vite@npm:6.3.5" dependencies: - makeerror: "npm:1.0.12" - checksum: 10/ad7a257ea1e662e57ef2e018f97b3c02a7240ad5093c392186ce0bcf1f1a60bbadd520d073b9beb921ed99f64f065efb63dfc8eec689a80e569f93c1c5d5e16c + esbuild: "npm:^0.25.0" + fdir: "npm:^6.4.4" + fsevents: "npm:~2.3.3" + picomatch: "npm:^4.0.2" + postcss: "npm:^8.5.3" + rollup: "npm:^4.34.9" + tinyglobby: "npm:^0.2.13" + peerDependencies: + "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: ">=1.21.0" + less: "*" + lightningcss: ^1.21.0 + sass: "*" + sass-embedded: "*" + stylus: "*" + sugarss: "*" + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + bin: + vite: bin/vite.js + checksum: 10/7bc3a1c5ef79413ad70daeeaf69b76cd1218d16aa18ed8ee08d74648ef17284f4a17c11f5cf42b573b6dc5e3d5f115110b67b1d23c2c699cfe404757764a634a + languageName: node + linkType: hard + +"vitest@npm:^3.1.3": + version: 3.1.3 + resolution: "vitest@npm:3.1.3" + dependencies: + "@vitest/expect": "npm:3.1.3" + "@vitest/mocker": "npm:3.1.3" + "@vitest/pretty-format": "npm:^3.1.3" + "@vitest/runner": "npm:3.1.3" + "@vitest/snapshot": "npm:3.1.3" + "@vitest/spy": "npm:3.1.3" + "@vitest/utils": "npm:3.1.3" + chai: "npm:^5.2.0" + debug: "npm:^4.4.0" + expect-type: "npm:^1.2.1" + magic-string: "npm:^0.30.17" + pathe: "npm:^2.0.3" + std-env: "npm:^3.9.0" + tinybench: "npm:^2.9.0" + tinyexec: "npm:^0.3.2" + tinyglobby: "npm:^0.2.13" + tinypool: "npm:^1.0.2" + tinyrainbow: "npm:^2.0.0" + vite: "npm:^5.0.0 || ^6.0.0" + vite-node: "npm:3.1.3" + why-is-node-running: "npm:^2.3.0" + peerDependencies: + "@edge-runtime/vm": "*" + "@types/debug": ^4.1.12 + "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + "@vitest/browser": 3.1.3 + "@vitest/ui": 3.1.3 + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@types/debug": + optional: true + "@types/node": + optional: true + "@vitest/browser": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + bin: + vitest: vitest.mjs + checksum: 10/ae74b401b15847615ec664260cf83eb2ce67c4bf018228bd0c48eae2e94309104a8a49b42ef422c27905e438d367207da15364d500f72cf2b723aff448c6a4e6 languageName: node linkType: hard @@ -4016,7 +2379,19 @@ __metadata: languageName: node linkType: hard -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": +"why-is-node-running@npm:^2.3.0": + version: 2.3.0 + resolution: "why-is-node-running@npm:2.3.0" + dependencies: + siginfo: "npm:^2.0.0" + stackback: "npm:0.0.2" + bin: + why-is-node-running: cli.js + checksum: 10/0de6e6cd8f2f94a8b5ca44e84cf1751eadcac3ebedcdc6e5fbbe6c8011904afcbc1a2777c53496ec02ced7b81f2e7eda61e76bf8262a8bc3ceaa1f6040508051 + languageName: node + linkType: hard + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" dependencies: @@ -4038,37 +2413,6 @@ __metadata: languageName: node linkType: hard -"wrappy@npm:1": - version: 1.0.2 - resolution: "wrappy@npm:1.0.2" - checksum: 10/159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 - languageName: node - linkType: hard - -"write-file-atomic@npm:^4.0.2": - version: 4.0.2 - resolution: "write-file-atomic@npm:4.0.2" - dependencies: - imurmurhash: "npm:^0.1.4" - signal-exit: "npm:^3.0.7" - checksum: 10/3be1f5508a46c190619d5386b1ac8f3af3dbe951ed0f7b0b4a0961eed6fc626bd84b50cf4be768dabc0a05b672f5d0c5ee7f42daa557b14415d18c3a13c7d246 - languageName: node - linkType: hard - -"y18n@npm:^5.0.5": - version: 5.0.8 - resolution: "y18n@npm:5.0.8" - checksum: 10/5f1b5f95e3775de4514edbb142398a2c37849ccfaf04a015be5d75521e9629d3be29bd4432d23c57f37e5b61ade592fb0197022e9993f81a06a5afbdcda9346d - languageName: node - linkType: hard - -"yallist@npm:^3.0.2": - version: 3.1.1 - resolution: "yallist@npm:3.1.1" - checksum: 10/9af0a4329c3c6b779ac4736c69fae4190ac03029fa27c1aef4e6bcc92119b73dea6fe5db5fe881fb0ce2a0e9539a42cdf60c7c21eda04d1a0b8c082e38509efb - languageName: node - linkType: hard - "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" @@ -4083,28 +2427,6 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^21.1.1": - version: 21.1.1 - resolution: "yargs-parser@npm:21.1.1" - checksum: 10/9dc2c217ea3bf8d858041252d43e074f7166b53f3d010a8c711275e09cd3d62a002969a39858b92bbda2a6a63a585c7127014534a560b9c69ed2d923d113406e - languageName: node - linkType: hard - -"yargs@npm:^17.3.1": - version: 17.7.2 - resolution: "yargs@npm:17.7.2" - dependencies: - cliui: "npm:^8.0.1" - escalade: "npm:^3.1.1" - get-caller-file: "npm:^2.0.5" - require-directory: "npm:^2.1.1" - string-width: "npm:^4.2.3" - y18n: "npm:^5.0.5" - yargs-parser: "npm:^21.1.1" - checksum: 10/abb3e37678d6e38ea85485ed86ebe0d1e3464c640d7d9069805ea0da12f69d5a32df8e5625e370f9c96dd1c2dc088ab2d0a4dd32af18222ef3c4224a19471576 - languageName: node - linkType: hard - "yn@npm:3.1.1": version: 3.1.1 resolution: "yn@npm:3.1.1" @@ -4112,13 +2434,6 @@ __metadata: languageName: node linkType: hard -"yocto-queue@npm:^0.1.0": - version: 0.1.0 - resolution: "yocto-queue@npm:0.1.0" - checksum: 10/f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 - languageName: node - linkType: hard - "yoctocolors@npm:^2.1.1": version: 2.1.1 resolution: "yoctocolors@npm:2.1.1" From ef8d5bffce057a81398245ce84dd26cb37893109 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 17 May 2025 11:53:49 -0500 Subject: [PATCH 078/282] use vitest run, remove vitest ui dep --- contracts/utils/package.json | 2 +- package.json | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 4f0ee469..5b9fab30 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -15,7 +15,7 @@ "scripts": { "compact": "npx compact-compiler", "build": "npx compact-builder && tsc", - "test": "vitest", + "test": "vitest run", "types": "tsc -p tsconfig.json --noEmit", "fmt": "biome format", "fmt:fix": "biome format --write", diff --git a/package.json b/package.json index e1c31350..3f7d1f73 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "@midnight-ntwrk/ledger": "^4.0.0", "@midnight-ntwrk/zswap": "^4.0.0", "@types/node": "^18.18.6", - "@vitest/ui": "^3.1.3", "fast-check": "^3.15.0", "ts-node": "^10.9.2", "turbo": "^2.5.1", From a9df304a42b0821d89f205735537adb41c10fd35 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 17 May 2025 16:53:11 -0500 Subject: [PATCH 079/282] add vitest imports for testing --- contracts/utils/src/test/Initializable.test.ts | 2 +- contracts/utils/src/test/Pausable.test.ts | 2 +- contracts/utils/src/test/utils.test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/utils/src/test/Initializable.test.ts b/contracts/utils/src/test/Initializable.test.ts index 21a81929..3396b844 100644 --- a/contracts/utils/src/test/Initializable.test.ts +++ b/contracts/utils/src/test/Initializable.test.ts @@ -1,5 +1,5 @@ import { InitializableSimulator } from './simulators/InitializableSimulator'; -import { expect } from 'vitest' +import { describe, it, expect, beforeEach } from 'vitest' let initializable: InitializableSimulator; diff --git a/contracts/utils/src/test/Pausable.test.ts b/contracts/utils/src/test/Pausable.test.ts index 1098e7af..7bfa265f 100644 --- a/contracts/utils/src/test/Pausable.test.ts +++ b/contracts/utils/src/test/Pausable.test.ts @@ -1,4 +1,4 @@ -import { expect } from 'vitest' +import { describe, it, expect, beforeEach } from 'vitest' import { PausableSimulator } from './simulators/PausableSimulator'; let pausable: PausableSimulator; diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 42ac1a27..3bc57c24 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -1,6 +1,6 @@ import { UtilsSimulator } from './simulators/UtilsSimulator'; import * as contractUtils from './utils/address'; -import { expect } from 'vitest' +import { describe, it, expect } from 'vitest' const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); From 22aa2cae097ca0dc94006977711c94575d20ea4f Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 17 May 2025 16:53:34 -0500 Subject: [PATCH 080/282] remove vitest ui --- yarn.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index c8976613..1b058ddc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1810,7 +1810,6 @@ __metadata: "@midnight-ntwrk/ledger": "npm:^4.0.0" "@midnight-ntwrk/zswap": "npm:^4.0.0" "@types/node": "npm:^18.18.6" - "@vitest/ui": "npm:^3.1.3" fast-check: "npm:^3.15.0" ts-node: "npm:^10.9.2" turbo: "npm:^2.5.1" From 2fbb088addeb131b9bf26d845fd01d149ea93d75 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 17 May 2025 16:54:42 -0500 Subject: [PATCH 081/282] bump compact-runtime to 0.8.1 --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 3f7d1f73..0032c75b 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "clean": "turbo run clean" }, "dependencies": { - "@midnight-ntwrk/compact-runtime": "^0.8.0" + "@midnight-ntwrk/compact-runtime": "^0.8.1" }, "devDependencies": { "@biomejs/biome": "1.9.4", diff --git a/yarn.lock b/yarn.lock index 1b058ddc..aacd1bd1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -327,7 +327,7 @@ __metadata: languageName: node linkType: hard -"@midnight-ntwrk/compact-runtime@npm:^0.8.0": +"@midnight-ntwrk/compact-runtime@npm:^0.8.1": version: 0.8.1 resolution: "@midnight-ntwrk/compact-runtime@npm:0.8.1" dependencies: @@ -1806,7 +1806,7 @@ __metadata: resolution: "root-workspace-0b6124@workspace:." dependencies: "@biomejs/biome": "npm:1.9.4" - "@midnight-ntwrk/compact-runtime": "npm:^0.8.0" + "@midnight-ntwrk/compact-runtime": "npm:^0.8.1" "@midnight-ntwrk/ledger": "npm:^4.0.0" "@midnight-ntwrk/zswap": "npm:^4.0.0" "@types/node": "npm:^18.18.6" From ed6f759c207397ea9dbe412a4e8da6e5c7a769fd Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 17 May 2025 16:55:05 -0500 Subject: [PATCH 082/282] set vitest reporters to verbose --- contracts/utils/vitest.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/utils/vitest.config.ts b/contracts/utils/vitest.config.ts index 72f7fab7..785b792e 100644 --- a/contracts/utils/vitest.config.ts +++ b/contracts/utils/vitest.config.ts @@ -5,5 +5,6 @@ export default defineConfig({ globals: true, environment: 'node', include: ['src/test/**/*.test.ts'], + reporters: 'verbose', }, }); From e1f6f723d6e23b79e6c6e454685213015e257e82 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 17 May 2025 23:39:17 -0500 Subject: [PATCH 083/282] fix fmt --- compact/package.json | 5 +---- contracts/utils/src/test/Initializable.test.ts | 2 +- contracts/utils/src/test/Pausable.test.ts | 2 +- contracts/utils/src/test/utils.test.ts | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compact/package.json b/compact/package.json index 8ee95ee9..ac08934d 100644 --- a/compact/package.json +++ b/compact/package.json @@ -2,10 +2,7 @@ "packageManager": "yarn@4.1.0", "name": "@openzeppelin-midnight/compact", "version": "0.0.1", - "keywords": [ - "compact", - "compiler" - ], + "keywords": ["compact", "compiler"], "author": "", "license": "MIT", "description": "Compact fetcher", diff --git a/contracts/utils/src/test/Initializable.test.ts b/contracts/utils/src/test/Initializable.test.ts index 3396b844..1287183f 100644 --- a/contracts/utils/src/test/Initializable.test.ts +++ b/contracts/utils/src/test/Initializable.test.ts @@ -1,5 +1,5 @@ import { InitializableSimulator } from './simulators/InitializableSimulator'; -import { describe, it, expect, beforeEach } from 'vitest' +import { describe, it, expect, beforeEach } from 'vitest'; let initializable: InitializableSimulator; diff --git a/contracts/utils/src/test/Pausable.test.ts b/contracts/utils/src/test/Pausable.test.ts index 7bfa265f..e8c36006 100644 --- a/contracts/utils/src/test/Pausable.test.ts +++ b/contracts/utils/src/test/Pausable.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, beforeEach } from 'vitest' +import { describe, it, expect, beforeEach } from 'vitest'; import { PausableSimulator } from './simulators/PausableSimulator'; let pausable: PausableSimulator; diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 3bc57c24..e001b652 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -1,6 +1,6 @@ import { UtilsSimulator } from './simulators/UtilsSimulator'; import * as contractUtils from './utils/address'; -import { describe, it, expect } from 'vitest' +import { describe, it, expect } from 'vitest'; const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); From 397f5e4c9d949061d0c68e4f1f316ed1d7a2d1cc Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 17 May 2025 23:40:24 -0500 Subject: [PATCH 084/282] fix lint --- contracts/utils/src/test/Initializable.test.ts | 2 +- contracts/utils/src/test/Pausable.test.ts | 2 +- contracts/utils/src/test/utils.test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/utils/src/test/Initializable.test.ts b/contracts/utils/src/test/Initializable.test.ts index 1287183f..125d253b 100644 --- a/contracts/utils/src/test/Initializable.test.ts +++ b/contracts/utils/src/test/Initializable.test.ts @@ -1,5 +1,5 @@ +import { beforeEach, describe, expect, it } from 'vitest'; import { InitializableSimulator } from './simulators/InitializableSimulator'; -import { describe, it, expect, beforeEach } from 'vitest'; let initializable: InitializableSimulator; diff --git a/contracts/utils/src/test/Pausable.test.ts b/contracts/utils/src/test/Pausable.test.ts index e8c36006..0a16e444 100644 --- a/contracts/utils/src/test/Pausable.test.ts +++ b/contracts/utils/src/test/Pausable.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, beforeEach } from 'vitest'; +import { beforeEach, describe, expect, it } from 'vitest'; import { PausableSimulator } from './simulators/PausableSimulator'; let pausable: PausableSimulator; diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index e001b652..f99953ac 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -1,6 +1,6 @@ +import { describe, expect, it } from 'vitest'; import { UtilsSimulator } from './simulators/UtilsSimulator'; import * as contractUtils from './utils/address'; -import { describe, it, expect } from 'vitest'; const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); From 4a63222f5a36d03bac76f1c2024bff573a821565 Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 18 May 2025 20:36:41 -0500 Subject: [PATCH 085/282] remove unused dep --- contracts/utils/package.json | 1 - yarn.lock | 65 ------------------------------------ 2 files changed, 66 deletions(-) diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 5b9fab30..99d724da 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -30,7 +30,6 @@ "@openzeppelin-midnight/compact": "workspace:^", "@biomejs/biome": "1.9.4", "@types/node": "^18.18.6", - "@vitest/ui": "^3.1.3", "ts-node": "^10.9.2", "typescript": "^5.2.2", "vitest": "^3.1.3" diff --git a/yarn.lock b/yarn.lock index aacd1bd1..9339f2db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -404,7 +404,6 @@ __metadata: "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:^18.18.6" - "@vitest/ui": "npm:^3.1.3" ts-node: "npm:^10.9.2" typescript: "npm:^5.2.2" vitest: "npm:^3.1.3" @@ -418,7 +417,6 @@ __metadata: "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:^18.18.6" - "@vitest/ui": "npm:^3.1.3" ts-node: "npm:^10.9.2" typescript: "npm:^5.2.2" vitest: "npm:^3.1.3" @@ -432,13 +430,6 @@ __metadata: languageName: node linkType: hard -"@polka/url@npm:^1.0.0-next.24": - version: 1.0.0-next.29 - resolution: "@polka/url@npm:1.0.0-next.29" - checksum: 10/69ca11ab15a4ffec7f0b07fcc4e1f01489b3d9683a7e1867758818386575c60c213401259ba3705b8a812228d17e2bfd18e6f021194d943fff4bca389c9d4f28 - languageName: node - linkType: hard - "@rollup/rollup-android-arm-eabi@npm:4.40.2": version: 4.40.2 resolution: "@rollup/rollup-android-arm-eabi@npm:4.40.2" @@ -709,23 +700,6 @@ __metadata: languageName: node linkType: hard -"@vitest/ui@npm:^3.1.3": - version: 3.1.3 - resolution: "@vitest/ui@npm:3.1.3" - dependencies: - "@vitest/utils": "npm:3.1.3" - fflate: "npm:^0.8.2" - flatted: "npm:^3.3.3" - pathe: "npm:^2.0.3" - sirv: "npm:^3.0.1" - tinyglobby: "npm:^0.2.13" - tinyrainbow: "npm:^2.0.0" - peerDependencies: - vitest: 3.1.3 - checksum: 10/e59b6772b21b97d64428746adc81cf61bf8b04a72bb6178504d8fff2dd02f50e8daada8815f6351f9575dbb8e7880b0dfff2a363b3beee4d9475a4402dcb4afe - languageName: node - linkType: hard - "@vitest/utils@npm:3.1.3": version: 3.1.3 resolution: "@vitest/utils@npm:3.1.3" @@ -1154,20 +1128,6 @@ __metadata: languageName: node linkType: hard -"fflate@npm:^0.8.2": - version: 0.8.2 - resolution: "fflate@npm:0.8.2" - checksum: 10/2bd26ba6d235d428de793c6a0cd1aaa96a06269ebd4e21b46c8fd1bd136abc631acf27e188d47c3936db090bf3e1ede11d15ce9eae9bffdc4bfe1b9dc66ca9cb - languageName: node - linkType: hard - -"flatted@npm:^3.3.3": - version: 3.3.3 - resolution: "flatted@npm:3.3.3" - checksum: 10/8c96c02fbeadcf4e8ffd0fa24983241e27698b0781295622591fc13585e2f226609d95e422bcf2ef044146ffacb6b68b1f20871454eddf75ab3caa6ee5f4a1fe - languageName: node - linkType: hard - "foreground-child@npm:^3.1.0": version: 3.3.1 resolution: "foreground-child@npm:3.3.1" @@ -1521,13 +1481,6 @@ __metadata: languageName: node linkType: hard -"mrmime@npm:^2.0.0": - version: 2.0.1 - resolution: "mrmime@npm:2.0.1" - checksum: 10/1f966e2c05b7264209c4149ae50e8e830908eb64dd903535196f6ad72681fa109b794007288a3c2814f7a1ecf9ca192769909c0c374d974d604a8de5fc095d4a - languageName: node - linkType: hard - "ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" @@ -1864,17 +1817,6 @@ __metadata: languageName: node linkType: hard -"sirv@npm:^3.0.1": - version: 3.0.1 - resolution: "sirv@npm:3.0.1" - dependencies: - "@polka/url": "npm:^1.0.0-next.24" - mrmime: "npm:^2.0.0" - totalist: "npm:^3.0.0" - checksum: 10/b110ebe28eb1740772fbbfacb6c71c58d1ec8ec17a5ae2852a5418c3ef41d52d473663613de808f8a6337ec29dd446414d0d059e75bfd13fb9630d18651c99f2 - languageName: node - linkType: hard - "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" @@ -2057,13 +1999,6 @@ __metadata: languageName: node linkType: hard -"totalist@npm:^3.0.0": - version: 3.0.1 - resolution: "totalist@npm:3.0.1" - checksum: 10/5132d562cf88ff93fd710770a92f31dbe67cc19b5c6ccae2efc0da327f0954d211bbfd9456389655d726c624f284b4a23112f56d1da931ca7cfabbe1f45e778a - languageName: node - linkType: hard - "ts-node@npm:^10.9.2": version: 10.9.2 resolution: "ts-node@npm:10.9.2" From 474921a3a596f78cf0f3ba0fe6a9b1ac80af232c Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Mon, 19 May 2025 19:12:00 -0400 Subject: [PATCH 086/282] Update pragma to new version, import path --- contracts/erc721/src/ERC721.compact | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index da381fdc..7e8673ce 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma language_version >= 0.14.0; +pragma language_version >= 0.15.0; /** * @module ERC721 @@ -18,7 +18,7 @@ pragma language_version >= 0.14.0; */ module ERC721 { import CompactStandardLibrary; - import "../../node_modules/@openzeppelin-midnight-contracts/utils-contract/src/Utils" prefix Utils_; + import "../../node_modules/@openzeppelin-midnight/utils/src/Utils" prefix Utils_; /// Public state export sealed ledger _name: Maybe>; From 89072064a920e852f6d446a448d00cd4a2edc58c Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Mon, 19 May 2025 19:12:37 -0400 Subject: [PATCH 087/282] Add vitest config --- contracts/erc721/vitest.config.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 contracts/erc721/vitest.config.ts diff --git a/contracts/erc721/vitest.config.ts b/contracts/erc721/vitest.config.ts new file mode 100644 index 00000000..785b792e --- /dev/null +++ b/contracts/erc721/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['src/test/**/*.test.ts'], + reporters: 'verbose', + }, +}); From 728b6ad2cb93cea7099f5bdd74c6125ea8fa54c9 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Mon, 19 May 2025 19:41:03 -0400 Subject: [PATCH 088/282] Fix biome lints --- compact/package.json | 5 ++++- contracts/erc721/src/test/erc721.test.ts | 19 ++++++++++--------- .../src/test/simulators/ERC721Simulator.ts | 14 ++++++-------- contracts/erc721/src/test/simulators/index.ts | 1 - contracts/erc721/src/test/types/string.ts | 4 ++++ .../erc721/src/witnesses/ERC721Witnesses.ts | 4 ++-- contracts/erc721/src/witnesses/index.ts | 2 -- yarn.lock | 13 +++++++++++++ 8 files changed, 39 insertions(+), 23 deletions(-) delete mode 100644 contracts/erc721/src/test/simulators/index.ts create mode 100644 contracts/erc721/src/test/types/string.ts delete mode 100644 contracts/erc721/src/witnesses/index.ts diff --git a/compact/package.json b/compact/package.json index ac08934d..8ee95ee9 100644 --- a/compact/package.json +++ b/compact/package.json @@ -2,7 +2,10 @@ "packageManager": "yarn@4.1.0", "name": "@openzeppelin-midnight/compact", "version": "0.0.1", - "keywords": ["compact", "compiler"], + "keywords": [ + "compact", + "compiler" + ], "author": "", "license": "MIT", "description": "Compact fetcher", diff --git a/contracts/erc721/src/test/erc721.test.ts b/contracts/erc721/src/test/erc721.test.ts index 518bd866..2f47b68e 100644 --- a/contracts/erc721/src/test/erc721.test.ts +++ b/contracts/erc721/src/test/erc721.test.ts @@ -1,7 +1,8 @@ -import { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; -import { ERC721Simulator } from './simulators'; -import { MaybeString } from './types'; -import * as utils from './utils'; +import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; +import { beforeEach, describe, expect, it } from 'vitest'; +import { ERC721Simulator } from './simulators/ERC721Simulator'; +import type { MaybeString } from './types/string'; +import {createEitherTestContractAddress, createEitherTestUser} from './utils/address'; const NO_STRING: MaybeString = { is_some: false, @@ -25,11 +26,11 @@ const OWNER = String(Buffer.from("OWNER", 'ascii').toString('hex')).padStart(64, const SPENDER = String(Buffer.from("SPENDER", 'ascii').toString('hex')).padStart(64, '0'); const UNAUTHORIZED = String(Buffer.from("UNAUTHORIZED", 'ascii').toString('hex')).padStart(64, '0'); const ZERO = String().padStart(64, '0'); -const Z_OWNER = utils.createEitherTestUser('OWNER'); -const Z_RECIPIENT = utils.createEitherTestUser('RECIPIENT'); -const Z_SPENDER = utils.createEitherTestUser('SPENDER'); -const Z_OTHER = utils.createEitherTestUser('OTHER'); -const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); +const Z_OWNER = createEitherTestUser('OWNER'); +const Z_RECIPIENT = createEitherTestUser('RECIPIENT'); +const Z_SPENDER = createEitherTestUser('SPENDER'); +const Z_OTHER = createEitherTestUser('OTHER'); +const SOME_CONTRACT = createEitherTestContractAddress('SOME_CONTRACT'); let token: ERC721Simulator; let caller: CoinPublicKey; diff --git a/contracts/erc721/src/test/simulators/ERC721Simulator.ts b/contracts/erc721/src/test/simulators/ERC721Simulator.ts index 8660d422..8d60a07b 100644 --- a/contracts/erc721/src/test/simulators/ERC721Simulator.ts +++ b/contracts/erc721/src/test/simulators/ERC721Simulator.ts @@ -1,24 +1,22 @@ import { type CircuitContext, - CoinPublicKey, type ContractState, QueryContext, constructorContext, - emptyZswapLocalState, } from '@midnight-ntwrk/compact-runtime'; import { sampleContractAddress } from '@midnight-ntwrk/zswap'; import { type Ledger, Contract as MockERC721, ledger, - Either, - ZswapCoinPublicKey, - ContractAddress, + type Either, + type ZswapCoinPublicKey, + type ContractAddress, pureCircuits } from '../../artifacts/MockERC721/contract/index.cjs'; // Combined imports -import { MaybeString } from '../types'; -import type { IContractSimulator } from '../types'; -import { ERC721PrivateState, ERC721Witnesses } from '../../witnesses'; +import type { MaybeString } from '../types/string'; +import type { IContractSimulator } from '../types/test'; +import { type ERC721PrivateState, ERC721Witnesses } from '../../witnesses/ERC721Witnesses'; /** * @description A simulator implementation of an ERC721 contract for testing purposes. diff --git a/contracts/erc721/src/test/simulators/index.ts b/contracts/erc721/src/test/simulators/index.ts deleted file mode 100644 index 21479682..00000000 --- a/contracts/erc721/src/test/simulators/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { ERC721Simulator } from './ERC721Simulator'; diff --git a/contracts/erc721/src/test/types/string.ts b/contracts/erc721/src/test/types/string.ts new file mode 100644 index 00000000..430a139e --- /dev/null +++ b/contracts/erc721/src/test/types/string.ts @@ -0,0 +1,4 @@ +export type MaybeString = { + is_some: boolean; + value: string; +}; diff --git a/contracts/erc721/src/witnesses/ERC721Witnesses.ts b/contracts/erc721/src/witnesses/ERC721Witnesses.ts index e6747b1c..273ca2e0 100644 --- a/contracts/erc721/src/witnesses/ERC721Witnesses.ts +++ b/contracts/erc721/src/witnesses/ERC721Witnesses.ts @@ -1,5 +1,5 @@ -import * as Contract from "../artifacts/MockERC721/contract/index.cjs"; -import { WitnessContext } from "@midnight-ntwrk/compact-runtime"; +import type * as Contract from "../artifacts/MockERC721/contract/index.cjs"; +import type { WitnessContext } from "@midnight-ntwrk/compact-runtime"; export type ERC721PrivateState = { tokenURI: string diff --git a/contracts/erc721/src/witnesses/index.ts b/contracts/erc721/src/witnesses/index.ts deleted file mode 100644 index 5b4961a0..00000000 --- a/contracts/erc721/src/witnesses/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../artifacts/erc721/contract/index.cjs'; -export * from './ERC721Witnesses.js'; diff --git a/yarn.lock b/yarn.lock index 9339f2db..c4007eee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -410,6 +410,19 @@ __metadata: languageName: unknown linkType: soft +"@openzeppelin-midnight/erc721@workspace:contracts/erc721": + version: 0.0.0-use.local + resolution: "@openzeppelin-midnight/erc721@workspace:contracts/erc721" + dependencies: + "@biomejs/biome": "npm:1.9.4" + "@openzeppelin-midnight/compact": "workspace:^" + "@types/node": "npm:^18.18.6" + ts-node: "npm:^10.9.2" + typescript: "npm:^5.2.2" + vitest: "npm:^3.1.3" + languageName: unknown + linkType: soft + "@openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" From b94dd81484c5acd7ff81b515b92d44f46120faa5 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Mon, 19 May 2025 19:41:15 -0400 Subject: [PATCH 089/282] Update pragma to latest version --- contracts/erc721/src/test/mocks/MockERC721.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/erc721/src/test/mocks/MockERC721.compact b/contracts/erc721/src/test/mocks/MockERC721.compact index 40b92c01..944ae950 100644 --- a/contracts/erc721/src/test/mocks/MockERC721.compact +++ b/contracts/erc721/src/test/mocks/MockERC721.compact @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma language_version >= 0.14.0; +pragma language_version >= 0.15.0; import CompactStandardLibrary; From a0fd35080ecd2fe08dd1347d6d44367991ddb027 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Sun, 18 May 2025 21:42:27 -0400 Subject: [PATCH 090/282] Add license (#44) * add license * add license * fix copyright year --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..e22ac902 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Zeppelin Group Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 0c548bc5f72cdb88f7c58485974a1e8e0a703b6a Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Mon, 19 May 2025 17:47:05 -0400 Subject: [PATCH 091/282] Support compact 0.23.0, migrate to vitest (#68) * migrate to vitest, bump compact-runtime * use vitest run, remove vitest ui dep * add vitest imports for testing * remove vitest ui * bump compact-runtime to 0.8.1 * set vitest reporters to verbose * fix fmt * fix lint * remove unused dep --- contracts/erc721/vitest.config.ts | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 contracts/erc721/vitest.config.ts diff --git a/contracts/erc721/vitest.config.ts b/contracts/erc721/vitest.config.ts deleted file mode 100644 index 785b792e..00000000 --- a/contracts/erc721/vitest.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from 'vitest/config'; - -export default defineConfig({ - test: { - globals: true, - environment: 'node', - include: ['src/test/**/*.test.ts'], - reporters: 'verbose', - }, -}); From 4d0593f9b1dd3b534e2f8d6e196e515cbe5f20ba Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 20 May 2025 01:02:59 -0400 Subject: [PATCH 092/282] Update .nvmrc (#73) * update nvmrc * bump @types/node --- .nvmrc | 2 +- package.json | 2 +- yarn.lock | 11 ++++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.nvmrc b/.nvmrc index a77793ec..517f3866 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -lts/hydrogen +v22.14.0 diff --git a/package.json b/package.json index 0032c75b..f0e0753e 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@biomejs/biome": "1.9.4", "@midnight-ntwrk/ledger": "^4.0.0", "@midnight-ntwrk/zswap": "^4.0.0", - "@types/node": "^18.18.6", + "@types/node": "^22", "fast-check": "^3.15.0", "ts-node": "^10.9.2", "turbo": "^2.5.1", diff --git a/yarn.lock b/yarn.lock index c4007eee..0dbeb3c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -627,6 +627,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^22": + version: 22.15.19 + resolution: "@types/node@npm:22.15.19" + dependencies: + undici-types: "npm:~6.21.0" + checksum: 10/02311c2b5dbf2e9e2c17497dc27858bcefbe12a81af0d9b81f865613d8d014726e0eb6cbebfbdb84a327c1b9f9da1347a65a7699ac58c8854fb4daf447031149 + languageName: node + linkType: hard + "@types/node@npm:^22.13.10": version: 22.15.2 resolution: "@types/node@npm:22.15.2" @@ -1775,7 +1784,7 @@ __metadata: "@midnight-ntwrk/compact-runtime": "npm:^0.8.1" "@midnight-ntwrk/ledger": "npm:^4.0.0" "@midnight-ntwrk/zswap": "npm:^4.0.0" - "@types/node": "npm:^18.18.6" + "@types/node": "npm:^22" fast-check: "npm:^3.15.0" ts-node: "npm:^10.9.2" turbo: "npm:^2.5.1" From b9f4c0482c22616ca5355b867bc904725cda30a8 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Tue, 20 May 2025 14:21:57 -0400 Subject: [PATCH 093/282] Remove Either from public function signatures --- contracts/erc721/src/ERC721.compact | 55 ++++++++++--------- .../erc721/src/test/mocks/MockERC721.compact | 18 +++--- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 7e8673ce..5888ed66 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -77,15 +77,16 @@ module ERC721 { * * @dev Manually checks if `account` is a key in the map and returns 0 if it is not. * - * @param {account} - The public key or contract address to query. + * @param {account} - The public key to query. * @return {Uint<128>} - The account's token balance. */ - export circuit balanceOf(account: Either): Uint<128> { - if (!_balances.member(account)) { + export circuit balanceOf(account: ZswapCoinPublicKey): Uint<128> { + const acct = left(account); + if (!_balances.member(acct)) { return 0; } - return _balances.lookup(account); + return _balances.lookup(acct); } /** @@ -94,10 +95,10 @@ module ERC721 { * @dev Tokens assigned to zero address are considered invalid, and queries about them do throw. * * @param {tokenId} - The identifier for a token. - * @return {Either} - The public key or contract that owns the token. + * @return {ZswapCoinPublicKey} - The public key that owns the token. */ - export circuit ownerOf(tokenId: Field): Either { - return _requireOwned(tokenId); + export circuit ownerOf(tokenId: Field): ZswapCoinPublicKey { + return _requireOwned(tokenId).left; } export circuit tokenURI(tokenId: Field): Opaque<"string"> { @@ -112,65 +113,69 @@ module ERC721 { } export circuit approve( - to: Either, + to: ZswapCoinPublicKey, tokenId: Field ): [] { // TMP - Waiting for contract-to-contract calls to handle `right` with contract address const auth = left(own_public_key()); _approve( - to, + left(to), tokenId, auth ); } - export circuit getApproved(tokenId: Field): Either { + export circuit getApproved(tokenId: Field): ZswapCoinPublicKey { _requireOwned(tokenId); - return _getApproved(tokenId); + return _getApproved(tokenId).left; } export circuit setApprovalForAll( - operator: Either, + operator: ZswapCoinPublicKey, approved: Boolean ): [] { // TMP - Waiting for contract-to-contract calls to handle `right` with contract address const owner = left(own_public_key()); _setApprovalForAll( owner, - operator, + left(operator), approved ); } export circuit isApprovedForAll( - owner: Either, - operator: Either + owner: ZswapCoinPublicKey, + operator: ZswapCoinPublicKey ): Boolean { - if (_operatorApprovals.member(owner) && _operatorApprovals.lookup(owner).member(operator)) { - return _operatorApprovals.lookup(owner).lookup(operator); + const eitherOwner = left(owner); + const eitherOperator = left(operator); + if (_operatorApprovals.member(eitherOwner) && _operatorApprovals.lookup(eitherOwner).member(eitherOperator)) { + return _operatorApprovals.lookup(eitherOwner).lookup(eitherOperator); } else { return false; } } export circuit transferFrom( - from: Either, - to: Either, + from: ZswapCoinPublicKey, + to: ZswapCoinPublicKey, tokenId: Field ): [] { - assert !Utils_isKeyOrAddressZero(to) "ERC721: Invalid Receiver"; + const eitherTo = left(to); + const eitherFrom = left(from); + assert !Utils_isKeyOrAddressZero(eitherTo) "ERC721: Invalid Receiver"; // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. // Assumes sender is a ZSwapPublicKey // Need to revisit once we have contract <> contract communication const previousOwner = _update( - to, + eitherTo, tokenId, left(own_public_key()) ); - assert previousOwner != from "ERC721: Incorrect Owner"; + assert previousOwner != eitherFrom "ERC721: Incorrect Owner"; } export circuit safeTransferFrom( @@ -187,7 +192,7 @@ module ERC721 { tokenId: Field, data: Opaque<"string"> ): [] { - transferFrom(from, to, tokenId); + transferFrom(from.left, to.left, tokenId); // See https://github.com/OpenZeppelin/midnight-contracts/issues/25 // ERC721Utils_checkOnERC721Received } @@ -244,7 +249,7 @@ module ERC721 { const owner = _requireOwned(tokenId); // We do not use _isAuthorized because single-token approvals should not be able to call approve - assert (!Utils_isKeyOrAddressZero(auth) && owner != auth && !isApprovedForAll(owner, auth)) "ERC721 Invalid Approver"; + assert (!Utils_isKeyOrAddressZero(auth) && owner != auth && !isApprovedForAll(owner.left, auth.left)) "ERC721 Invalid Approver"; } _tokenApprovals.insert(tokenId, to); @@ -266,7 +271,7 @@ module ERC721 { spender: Either, tokenId: Field ): Boolean { - return (!Utils_isKeyOrAddressZero(spender) && (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender)); + return (!Utils_isKeyOrAddressZero(spender) && (owner == spender || isApprovedForAll(owner.left, spender.left) || _getApproved(tokenId) == spender)); } export circuit _getApproved(tokenId: Field): Either { diff --git a/contracts/erc721/src/test/mocks/MockERC721.compact b/contracts/erc721/src/test/mocks/MockERC721.compact index 944ae950..4a61a462 100644 --- a/contracts/erc721/src/test/mocks/MockERC721.compact +++ b/contracts/erc721/src/test/mocks/MockERC721.compact @@ -23,11 +23,11 @@ export circuit symbol(): Maybe> { return ERC721_symbol(); } -export circuit balanceOf(account: Either): Uint<128> { +export circuit balanceOf(account: ZswapCoinPublicKey): Uint<128> { return ERC721_balanceOf(account); } -export circuit ownerOf(tokenId: Field): Either { +export circuit ownerOf(tokenId: Field): ZswapCoinPublicKey { return ERC721_ownerOf(tokenId); } @@ -36,33 +36,33 @@ export circuit tokenURI(tokenId: Field): Opaque<"string"> { } export circuit approve( - to: Either, + to: ZswapCoinPublicKey, tokenId: Field ): [] { return ERC721_approve(to, tokenId); } -export circuit getApproved(tokenId: Field): Either { +export circuit getApproved(tokenId: Field): ZswapCoinPublicKey { return ERC721_getApproved(tokenId); } export circuit setApprovalForAll( - operator: Either, + operator: ZswapCoinPublicKey, approved: Boolean ): [] { return ERC721_setApprovalForAll(operator, approved); } export circuit isApprovedForAll( - owner: Either, - operator: Either + owner: ZswapCoinPublicKey, + operator: ZswapCoinPublicKey ): Boolean { return ERC721_isApprovedForAll(owner, operator); } export circuit transferFrom( - from: Either, - to: Either, + from: ZswapCoinPublicKey, + to: ZswapCoinPublicKey, tokenId: Field ): [] { return ERC721_transferFrom(from, to, tokenId); From 28426bc164766ac1cffc668a629b4384b0f80cef Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Tue, 20 May 2025 14:46:40 -0400 Subject: [PATCH 094/282] Remove _safeMint and _safeTransfer functions --- contracts/erc721/src/ERC721.compact | 35 ------------------- .../erc721/src/test/mocks/MockERC721.compact | 35 ------------------- 2 files changed, 70 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 5888ed66..44ff0081 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -178,25 +178,6 @@ module ERC721 { assert previousOwner != eitherFrom "ERC721: Incorrect Owner"; } - export circuit safeTransferFrom( - from: Either, - to: Either, - tokenId: Field - ): [] { - safeTransferFrom(from, to, tokenId, default>); - } - - export circuit safeTransferFrom( - from: Either, - to: Either, - tokenId: Field, - data: Opaque<"string"> - ): [] { - transferFrom(from.left, to.left, tokenId); - // See https://github.com/OpenZeppelin/midnight-contracts/issues/25 - // ERC721Utils_checkOnERC721Received - } - export circuit _requireOwned(tokenId: Field): Either { assert _owners.member(tokenId) "ERC721: Nonexistent Token"; const owner = _owners.lookup(tokenId); @@ -319,22 +300,6 @@ module ERC721 { assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Invalid Sender"; } - export circuit _safeMint( - to: Either, - tokenId: Field - ): [] { - _safeMint(to, tokenId, default>); - } - - export circuit _safeMint( - to: Either, - tokenId: Field, - data: Opaque<"string"> - ): [] { - _mint(to, tokenId); - // ERC721Utils_checkOnERC721Received - } - export circuit _burn(tokenId: Field): [] { const previousOwner = _update(burn_address(), tokenId, burn_address()); assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Nonexistent Token"; diff --git a/contracts/erc721/src/test/mocks/MockERC721.compact b/contracts/erc721/src/test/mocks/MockERC721.compact index 4a61a462..a979229e 100644 --- a/contracts/erc721/src/test/mocks/MockERC721.compact +++ b/contracts/erc721/src/test/mocks/MockERC721.compact @@ -68,24 +68,6 @@ export circuit transferFrom( return ERC721_transferFrom(from, to, tokenId); } -export circuit safeTransferFrom( - from: Either, - to: Either, - tokenId: Field -): [] { - return ERC721_safeTransferFrom(from, to, tokenId); -} - -// Two functions with the same name are not allowed as top-level exports -export circuit _safeTransferFrom( - from: Either, - to: Either, - tokenId: Field, - data: Opaque<"string"> -): [] { - return ERC721_safeTransferFrom(from, to, tokenId, data); -} - export circuit _requireOwned(tokenId: Field): Either { return ERC721__requireOwned(tokenId); } @@ -153,23 +135,6 @@ export circuit _mint( return ERC721__mint(to, tokenId); } -export circuit _safeMint( - to: Either, - tokenId: Field -): [] { - return ERC721__safeMint(to, tokenId); -} - - -// Two functions with the same name are not allowed as top-level exports -export circuit __safeMint( - to: Either, - tokenId: Field, - data: Opaque<"string"> -): [] { - return ERC721__safeMint(to, tokenId, data); -} - export circuit _burn(tokenId: Field): [] { return ERC721__burn(tokenId); } From 3d69160b8e17e3373e8da4b08c84878da7f7836e Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Tue, 20 May 2025 14:51:59 -0400 Subject: [PATCH 095/282] Remove _safe fns and update fn signatures in simulator --- .../src/test/simulators/ERC721Simulator.ts | 30 +++++-------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/contracts/erc721/src/test/simulators/ERC721Simulator.ts b/contracts/erc721/src/test/simulators/ERC721Simulator.ts index 8d60a07b..7fb6eed7 100644 --- a/contracts/erc721/src/test/simulators/ERC721Simulator.ts +++ b/contracts/erc721/src/test/simulators/ERC721Simulator.ts @@ -105,7 +105,7 @@ export class ERC721Simulator * @param account The public key or contract address to query. * @returns The account's token balance. */ - public balanceOf(account: Either): bigint { + public balanceOf(account: ZswapCoinPublicKey): bigint { return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; } @@ -114,7 +114,7 @@ export class ERC721Simulator * @param tokenId The Id of the token to query. * @returns The account owner of the token. */ - public ownerOf(tokenId: bigint): Either { + public ownerOf(tokenId: bigint): ZswapCoinPublicKey { return this.contract.impureCircuits.ownerOf(this.circuitContext, tokenId).result; } @@ -126,34 +126,26 @@ export class ERC721Simulator return pureCircuits._baseURI(); } - public approve(to: Either, tokenId: bigint): [] { + public approve(to: ZswapCoinPublicKey, tokenId: bigint): [] { return this.contract.impureCircuits.approve(this.circuitContext, to, tokenId).result; } - public getApproved(tokenId: bigint): Either { + public getApproved(tokenId: bigint): ZswapCoinPublicKey { return this.contract.impureCircuits.getApproved(this.circuitContext, tokenId).result; } - public setApprovalForAll(operator: Either, approved: boolean): [] { + public setApprovalForAll(operator: ZswapCoinPublicKey, approved: boolean): [] { return this.contract.impureCircuits.setApprovalForAll(this.circuitContext, operator, approved).result; } - public isApprovedForAll(owner: Either, operator: Either): boolean { + public isApprovedForAll(owner: ZswapCoinPublicKey, operator: ZswapCoinPublicKey): boolean { return this.contract.impureCircuits.isApprovedForAll(this.circuitContext, owner, operator).result; } - public transferFrom(from: Either, to: Either, tokenId: bigint): [] { + public transferFrom(from: ZswapCoinPublicKey, to: ZswapCoinPublicKey, tokenId: bigint): [] { return this.contract.impureCircuits.transferFrom(this.circuitContext, from, to, tokenId).result; } - public safeTransferFrom(from: Either, to: Either, tokenId: bigint): [] { - return this.contract.impureCircuits.safeTransferFrom(this.circuitContext, from, to, tokenId).result; - } - - public _safeTransferFromWith(from: Either, to: Either, tokenId: bigint, data: string): [] { - return this.contract.impureCircuits._safeTransferFrom(this.circuitContext, from, to, tokenId, data).result; - } - public _requireOwned(tokenId: bigint): Either { return this.contract.impureCircuits._requireOwned(this.circuitContext, tokenId).result; } @@ -194,14 +186,6 @@ export class ERC721Simulator return this.contract.impureCircuits._mint(this.circuitContext, to, tokenId).result; } - public _safeMint(to: Either, tokenId: bigint): [] { - return this.contract.impureCircuits._safeMint(this.circuitContext, to, tokenId).result; - } - - public __safeMint(to: Either, tokenId: bigint, data: string): [] { - return this.contract.impureCircuits.__safeMint(this.circuitContext, to, tokenId, data).result; - } - public _burn(tokenId: bigint): [] { return this.contract.impureCircuits._burn(this.circuitContext, tokenId).result; } From 13b2dc29bbb891e108a17217d9f8d90f472869ba Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Tue, 20 May 2025 15:34:28 -0400 Subject: [PATCH 096/282] update erc721 tests --- contracts/erc721/src/test/erc721.test.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/contracts/erc721/src/test/erc721.test.ts b/contracts/erc721/src/test/erc721.test.ts index 2f47b68e..f04d9028 100644 --- a/contracts/erc721/src/test/erc721.test.ts +++ b/contracts/erc721/src/test/erc721.test.ts @@ -2,7 +2,7 @@ import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; import { beforeEach, describe, expect, it } from 'vitest'; import { ERC721Simulator } from './simulators/ERC721Simulator'; import type { MaybeString } from './types/string'; -import {createEitherTestContractAddress, createEitherTestUser} from './utils/address'; +import {encodeToPK, createEitherTestContractAddress, createEitherTestUser} from './utils/address'; const NO_STRING: MaybeString = { is_some: false, @@ -26,7 +26,8 @@ const OWNER = String(Buffer.from("OWNER", 'ascii').toString('hex')).padStart(64, const SPENDER = String(Buffer.from("SPENDER", 'ascii').toString('hex')).padStart(64, '0'); const UNAUTHORIZED = String(Buffer.from("UNAUTHORIZED", 'ascii').toString('hex')).padStart(64, '0'); const ZERO = String().padStart(64, '0'); -const Z_OWNER = createEitherTestUser('OWNER'); +const Z_OWNER = encodeToPK('OWNER'); +const EITHER_Z_OWNER = createEitherTestUser('OWNER'); const Z_RECIPIENT = createEitherTestUser('RECIPIENT'); const Z_SPENDER = createEitherTestUser('SPENDER'); const Z_OTHER = createEitherTestUser('OTHER'); @@ -61,17 +62,17 @@ describe('ERC721', () => { expect(token.balanceOf(Z_OWNER)).toEqual(0n); }); - /* it('should return balance when requested account has tokens', () => { - token._mint(Z_OWNER, AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); */ + it('should return balance when requested account has tokens', () => { + token._mint(EITHER_Z_OWNER, AMOUNT); + expect(token.balanceOf(EITHER_Z_OWNER.left)).toEqual(AMOUNT); + }); }); describe('ownerOf', () => { it('should throw if tokenId does not exist', () => { expect(() => { token.ownerOf(TOKENID); - }).toThrow('ERC721: Invalid Owner'); + }).toThrow('ERC721: Nonexistent Token'); }) }) From 750941458655410065ab106e395ee9a6a5e3f814 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Tue, 20 May 2025 15:58:11 -0400 Subject: [PATCH 097/282] Fix typo --- contracts/erc721/src/ERC721.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 44ff0081..114c704e 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -291,7 +291,7 @@ module ERC721 { to: Either, tokenId: Field ): [] { - assert !Utils_isKeyOrAddressZero(to) "ERC721: Invald Receiver"; + assert !Utils_isKeyOrAddressZero(to) "ERC721: Invalid Receiver"; // Assumes burn_address == zero address // May want to define as default From 35f35b3df1c4ee6b775524227ddb3a3c0722db0d Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 21 May 2025 00:29:39 -0400 Subject: [PATCH 098/282] Add member checks to Map accesses, fix logic bug, update test --- contracts/erc721/src/ERC721.compact | 9 ++++++++- contracts/erc721/src/test/erc721.test.ts | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact index 114c704e..320ecf07 100644 --- a/contracts/erc721/src/ERC721.compact +++ b/contracts/erc721/src/ERC721.compact @@ -187,6 +187,10 @@ module ERC721 { } export circuit _ownerOf(tokenId: Field): Either { + if (!_owners.member(tokenId)) { + _owners.insert(tokenId, burn_address()); + } + return _owners.lookup(tokenId); } @@ -212,6 +216,9 @@ module ERC721 { } if (!Utils_isKeyOrAddressZero(to)) { + if (!_balances.member(to)) { + _balances.insert(to, 0); + } const newBalance = _balances.lookup(to) + 1 as Uint<128>; _balances.insert(to, newBalance); } @@ -297,7 +304,7 @@ module ERC721 { // May want to define as default const previousOwner = _update(to, tokenId, burn_address()); - assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Invalid Sender"; + assert Utils_isKeyOrAddressZero(previousOwner) "ERC721: Invalid Sender"; } export circuit _burn(tokenId: Field): [] { diff --git a/contracts/erc721/src/test/erc721.test.ts b/contracts/erc721/src/test/erc721.test.ts index f04d9028..2e15385e 100644 --- a/contracts/erc721/src/test/erc721.test.ts +++ b/contracts/erc721/src/test/erc721.test.ts @@ -19,7 +19,7 @@ const SYMBOL: MaybeString = { const TOKENID: bigint = BigInt(1); -const AMOUNT: bigint = BigInt(250); +const AMOUNT: bigint = BigInt(1); const MAX_UINT128 = BigInt(2 ** 128) - BigInt(1); const OWNER = String(Buffer.from("OWNER", 'ascii').toString('hex')).padStart(64, '0'); From 6aeb48305b33a6658eda6dd1827260a94b23a65f Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 17 May 2025 01:45:34 -0500 Subject: [PATCH 099/282] fix conflicts --- yarn.lock | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/yarn.lock b/yarn.lock index 0dbeb3c5..714ff9fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -423,6 +423,19 @@ __metadata: languageName: unknown linkType: soft +"@openzeppelin-midnight/erc721@workspace:contracts/erc721": + version: 0.0.0-use.local + resolution: "@openzeppelin-midnight/erc721@workspace:contracts/erc721" + dependencies: + "@biomejs/biome": "npm:1.9.4" + "@openzeppelin-midnight/compact": "workspace:^" + "@types/jest": "npm:^29.5.6" + "@types/node": "npm:^18.18.6" + jest: "npm:^29.7.0" + typescript: "npm:^5.2.2" + languageName: unknown + linkType: soft + "@openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" From 49fc02c2e1f521bd5c6dcc17c4bdbe70d721840e Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 18 May 2025 20:49:23 -0500 Subject: [PATCH 100/282] update yarnlock --- yarn.lock | 2553 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 2531 insertions(+), 22 deletions(-) diff --git a/yarn.lock b/yarn.lock index 714ff9fd..f0e98265 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,385 @@ __metadata: version: 8 cacheKey: 10 +"@ampproject/remapping@npm:^2.2.0": + version: 2.3.0 + resolution: "@ampproject/remapping@npm:2.3.0" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10/f3451525379c68a73eb0a1e65247fbf28c0cccd126d93af21c75fceff77773d43c0d4a2d51978fb131aff25b5f2cb41a9fe48cc296e61ae65e679c4f6918b0ab + languageName: node + linkType: hard + +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/code-frame@npm:7.27.1" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.27.1" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.1.1" + checksum: 10/721b8a6e360a1fa0f1c9fe7351ae6c874828e119183688b533c477aa378f1010f37cc9afbfc4722c686d1f5cdd00da02eab4ba7278a0c504fa0d7a321dcd4fdf + languageName: node + linkType: hard + +"@babel/compat-data@npm:^7.27.2": + version: 7.27.2 + resolution: "@babel/compat-data@npm:7.27.2" + checksum: 10/eaa9f8aaeb9475779f4411fa397f712a6441b650d4e0b40c5535c954c891cd35c0363004db42902192aa8224532ac31ce06890478b060995286fe4fadd54e542 + languageName: node + linkType: hard + +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.23.9": + version: 7.27.1 + resolution: "@babel/core@npm:7.27.1" + dependencies: + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.27.1" + "@babel/generator": "npm:^7.27.1" + "@babel/helper-compilation-targets": "npm:^7.27.1" + "@babel/helper-module-transforms": "npm:^7.27.1" + "@babel/helpers": "npm:^7.27.1" + "@babel/parser": "npm:^7.27.1" + "@babel/template": "npm:^7.27.1" + "@babel/traverse": "npm:^7.27.1" + "@babel/types": "npm:^7.27.1" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10/3dfec88f84b3ce567e6c482db0119f02f451bd3f86b0835c71c029fedb657969786507fafedd3a0732bd1be9fbc9f0635d734efafabad6dbc67d3eb7b494cdd8 + languageName: node + linkType: hard + +"@babel/generator@npm:^7.27.1, @babel/generator@npm:^7.7.2": + version: 7.27.1 + resolution: "@babel/generator@npm:7.27.1" + dependencies: + "@babel/parser": "npm:^7.27.1" + "@babel/types": "npm:^7.27.1" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^3.0.2" + checksum: 10/6101825922a8a116e64b507d9309b38c5bc027b333d7111fcb760422741d3c72bd8f8e5aa935c2944c434ffe376353a27afa3a25a8526dc2ef90743d266770db + languageName: node + linkType: hard + +"@babel/helper-compilation-targets@npm:^7.27.1": + version: 7.27.2 + resolution: "@babel/helper-compilation-targets@npm:7.27.2" + dependencies: + "@babel/compat-data": "npm:^7.27.2" + "@babel/helper-validator-option": "npm:^7.27.1" + browserslist: "npm:^4.24.0" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10/bd53c30a7477049db04b655d11f4c3500aea3bcbc2497cf02161de2ecf994fec7c098aabbcebe210ffabc2ecbdb1e3ffad23fb4d3f18723b814f423ea1749fe8 + languageName: node + linkType: hard + +"@babel/helper-module-imports@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-module-imports@npm:7.27.1" + dependencies: + "@babel/traverse": "npm:^7.27.1" + "@babel/types": "npm:^7.27.1" + checksum: 10/58e792ea5d4ae71676e0d03d9fef33e886a09602addc3bd01388a98d87df9fcfd192968feb40ac4aedb7e287ec3d0c17b33e3ecefe002592041a91d8a1998a8d + languageName: node + linkType: hard + +"@babel/helper-module-transforms@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-module-transforms@npm:7.27.1" + dependencies: + "@babel/helper-module-imports": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.27.1" + "@babel/traverse": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/415509a5854203073755aab3ad293664146a55777355b5b5187902f976162c9565907d2276f7f6e778527be4829db2d926015d446100a65f2538d6397d83e248 + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.27.1, @babel/helper-plugin-utils@npm:^7.8.0": + version: 7.27.1 + resolution: "@babel/helper-plugin-utils@npm:7.27.1" + checksum: 10/96136c2428888e620e2ec493c25888f9ceb4a21099dcf3dd4508ea64b58cdedbd5a9fb6c7b352546de84d6c24edafe482318646932a22c449ebd16d16c22d864 + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-string-parser@npm:7.27.1" + checksum: 10/0ae29cc2005084abdae2966afdb86ed14d41c9c37db02c3693d5022fba9f5d59b011d039380b8e537c34daf117c549f52b452398f576e908fb9db3c7abbb3a00 + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-validator-identifier@npm:7.27.1" + checksum: 10/75041904d21bdc0cd3b07a8ac90b11d64cd3c881e89cb936fa80edd734bf23c35e6bd1312611e8574c4eab1f3af0f63e8a5894f4699e9cfdf70c06fcf4252320 + languageName: node + linkType: hard + +"@babel/helper-validator-option@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-validator-option@npm:7.27.1" + checksum: 10/db73e6a308092531c629ee5de7f0d04390835b21a263be2644276cb27da2384b64676cab9f22cd8d8dbd854c92b1d7d56fc8517cf0070c35d1c14a8c828b0903 + languageName: node + linkType: hard + +"@babel/helpers@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helpers@npm:7.27.1" + dependencies: + "@babel/template": "npm:^7.27.1" + "@babel/types": "npm:^7.27.1" + checksum: 10/b86ee2c87d52640c63ec1fdf139d4560efc173ae6379659e0df49a3c0cf1d5f24436132ebb4459a4ee72418b43b39ee001f4e01465b48c8d31911a745ec4fd74 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.27.1, @babel/parser@npm:^7.27.2": + version: 7.27.2 + resolution: "@babel/parser@npm:7.27.2" + dependencies: + "@babel/types": "npm:^7.27.1" + bin: + parser: ./bin/babel-parser.js + checksum: 10/133b4ccfbc01d4f36b0945937aabff87026c29fda6dcd3c842053a672e50f2487a101a3acd150bbaa2eecd33f3bd35650f95b806567c926f93b2af35c2b615c9 + languageName: node + linkType: hard + +"@babel/plugin-syntax-async-generators@npm:^7.8.4": + version: 7.8.4 + resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.8.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/7ed1c1d9b9e5b64ef028ea5e755c0be2d4e5e4e3d6cf7df757b9a8c4cfa4193d268176d0f1f7fbecdda6fe722885c7fda681f480f3741d8a2d26854736f05367 + languageName: node + linkType: hard + +"@babel/plugin-syntax-bigint@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-bigint@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.8.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/3a10849d83e47aec50f367a9e56a6b22d662ddce643334b087f9828f4c3dd73bdc5909aaeabe123fed78515767f9ca43498a0e621c438d1cd2802d7fae3c9648 + languageName: node + linkType: hard + +"@babel/plugin-syntax-class-properties@npm:^7.12.13": + version: 7.12.13 + resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.12.13" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/24f34b196d6342f28d4bad303612d7ff566ab0a013ce89e775d98d6f832969462e7235f3e7eaf17678a533d4be0ba45d3ae34ab4e5a9dcbda5d98d49e5efa2fc + languageName: node + linkType: hard + +"@babel/plugin-syntax-class-static-block@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-class-static-block@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/3e80814b5b6d4fe17826093918680a351c2d34398a914ce6e55d8083d72a9bdde4fbaf6a2dcea0e23a03de26dc2917ae3efd603d27099e2b98380345703bf948 + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-attributes@npm:^7.24.7": + version: 7.27.1 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/97973982fff1bbf86b3d1df13380567042887c50e2ae13a400d02a8ff2c9742a60a75e279bfb73019e1cd9710f04be5e6ab81f896e6678dcfcec8b135e8896cf + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-meta@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.10.4" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/166ac1125d10b9c0c430e4156249a13858c0366d38844883d75d27389621ebe651115cb2ceb6dc011534d5055719fa1727b59f39e1ab3ca97820eef3dcab5b9b + languageName: node + linkType: hard + +"@babel/plugin-syntax-json-strings@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-json-strings@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.8.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/bf5aea1f3188c9a507e16efe030efb996853ca3cadd6512c51db7233cc58f3ac89ff8c6bdfb01d30843b161cfe7d321e1bf28da82f7ab8d7e6bc5464666f354a + languageName: node + linkType: hard + +"@babel/plugin-syntax-jsx@npm:^7.7.2": + version: 7.27.1 + resolution: "@babel/plugin-syntax-jsx@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/c6d1324cff286a369aa95d99b8abd21dd07821b5d3affd5fe7d6058c84cff9190743287826463ee57a7beecd10fa1e4bc99061df532ee14e188c1c8937b13e3a + languageName: node + linkType: hard + +"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.10.4" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/aff33577037e34e515911255cdbb1fd39efee33658aa00b8a5fd3a4b903585112d037cce1cc9e4632f0487dc554486106b79ccd5ea63a2e00df4363f6d4ff886 + languageName: node + linkType: hard + +"@babel/plugin-syntax-nullish-coalescing-operator@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-nullish-coalescing-operator@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.8.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/87aca4918916020d1fedba54c0e232de408df2644a425d153be368313fdde40d96088feed6c4e5ab72aac89be5d07fef2ddf329a15109c5eb65df006bf2580d1 + languageName: node + linkType: hard + +"@babel/plugin-syntax-numeric-separator@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/plugin-syntax-numeric-separator@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.10.4" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/01ec5547bd0497f76cc903ff4d6b02abc8c05f301c88d2622b6d834e33a5651aa7c7a3d80d8d57656a4588f7276eba357f6b7e006482f5b564b7a6488de493a1 + languageName: node + linkType: hard + +"@babel/plugin-syntax-object-rest-spread@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-object-rest-spread@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.8.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/fddcf581a57f77e80eb6b981b10658421bc321ba5f0a5b754118c6a92a5448f12a0c336f77b8abf734841e102e5126d69110a306eadb03ca3e1547cab31f5cbf + languageName: node + linkType: hard + +"@babel/plugin-syntax-optional-catch-binding@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-optional-catch-binding@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.8.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/910d90e72bc90ea1ce698e89c1027fed8845212d5ab588e35ef91f13b93143845f94e2539d831dc8d8ededc14ec02f04f7bd6a8179edd43a326c784e7ed7f0b9 + languageName: node + linkType: hard + +"@babel/plugin-syntax-optional-chaining@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-optional-chaining@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.8.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/eef94d53a1453361553c1f98b68d17782861a04a392840341bc91780838dd4e695209c783631cf0de14c635758beafb6a3a65399846ffa4386bff90639347f30 + languageName: node + linkType: hard + +"@babel/plugin-syntax-private-property-in-object@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-private-property-in-object@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/b317174783e6e96029b743ccff2a67d63d38756876e7e5d0ba53a322e38d9ca452c13354a57de1ad476b4c066dbae699e0ca157441da611117a47af88985ecda + languageName: node + linkType: hard + +"@babel/plugin-syntax-top-level-await@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-top-level-await@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/bbd1a56b095be7820029b209677b194db9b1d26691fe999856462e66b25b281f031f3dfd91b1619e9dcf95bebe336211833b854d0fb8780d618e35667c2d0d7e + languageName: node + linkType: hard + +"@babel/plugin-syntax-typescript@npm:^7.7.2": + version: 7.27.1 + resolution: "@babel/plugin-syntax-typescript@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/87836f7e32af624c2914c73cd6b9803cf324e07d43f61dbb973c6a86f75df725e12540d91fac7141c14b697aa9268fd064220998daced156e96ac3062d7afb41 + languageName: node + linkType: hard + +"@babel/template@npm:^7.27.1, @babel/template@npm:^7.3.3": + version: 7.27.2 + resolution: "@babel/template@npm:7.27.2" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@babel/parser": "npm:^7.27.2" + "@babel/types": "npm:^7.27.1" + checksum: 10/fed15a84beb0b9340e5f81566600dbee5eccd92e4b9cc42a944359b1aa1082373391d9d5fc3656981dff27233ec935d0bc96453cf507f60a4b079463999244d8 + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/traverse@npm:7.27.1" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@babel/generator": "npm:^7.27.1" + "@babel/parser": "npm:^7.27.1" + "@babel/template": "npm:^7.27.1" + "@babel/types": "npm:^7.27.1" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10/9977271aa451293d3f184521412788d6ddaff9d6a29626d7435b5dacd059feb2d7753bc94f59f4f5b76e65bd2e2cabc8a10d7e1f93709feda28619f2e8cbf4d6 + languageName: node + linkType: hard + +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.27.1, @babel/types@npm:^7.3.3": + version: 7.27.1 + resolution: "@babel/types@npm:7.27.1" + dependencies: + "@babel/helper-string-parser": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.27.1" + checksum: 10/81f8ada28c4b29695d7d4c4cbfaa5ec3138ccebbeb26628c7c3cc570fdc84f28967c9e68caf4977d51ff4f4d3159c88857ef278317f84f3515dd65e5b8a74995 + languageName: node + linkType: hard + +"@bcoe/v8-coverage@npm:^0.2.3": + version: 0.2.3 + resolution: "@bcoe/v8-coverage@npm:0.2.3" + checksum: 10/1a1f0e356a3bb30b5f1ced6f79c413e6ebacf130421f15fac5fcd8be5ddf98aedb4404d7f5624e3285b700e041f9ef938321f3ca4d359d5b716f96afa120d88d + languageName: node + linkType: hard + "@biomejs/biome@npm:1.9.4": version: 1.9.4 resolution: "@biomejs/biome@npm:1.9.4" @@ -303,14 +682,282 @@ __metadata: languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:^3.0.3": +"@istanbuljs/load-nyc-config@npm:^1.0.0": + version: 1.1.0 + resolution: "@istanbuljs/load-nyc-config@npm:1.1.0" + dependencies: + camelcase: "npm:^5.3.1" + find-up: "npm:^4.1.0" + get-package-type: "npm:^0.1.0" + js-yaml: "npm:^3.13.1" + resolve-from: "npm:^5.0.0" + checksum: 10/b000a5acd8d4fe6e34e25c399c8bdbb5d3a202b4e10416e17bfc25e12bab90bb56d33db6089ae30569b52686f4b35ff28ef26e88e21e69821d2b85884bd055b8 + languageName: node + linkType: hard + +"@istanbuljs/schema@npm:^0.1.2, @istanbuljs/schema@npm:^0.1.3": + version: 0.1.3 + resolution: "@istanbuljs/schema@npm:0.1.3" + checksum: 10/a9b1e49acdf5efc2f5b2359f2df7f90c5c725f2656f16099e8b2cd3a000619ecca9fc48cf693ba789cf0fd989f6e0df6a22bc05574be4223ecdbb7997d04384b + languageName: node + linkType: hard + +"@jest/console@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/console@npm:29.7.0" + dependencies: + "@jest/types": "npm:^29.6.3" + "@types/node": "npm:*" + chalk: "npm:^4.0.0" + jest-message-util: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + slash: "npm:^3.0.0" + checksum: 10/4a80c750e8a31f344233cb9951dee9b77bf6b89377cb131f8b3cde07ff218f504370133a5963f6a786af4d2ce7f85642db206ff7a15f99fe58df4c38ac04899e + languageName: node + linkType: hard + +"@jest/core@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/core@npm:29.7.0" + dependencies: + "@jest/console": "npm:^29.7.0" + "@jest/reporters": "npm:^29.7.0" + "@jest/test-result": "npm:^29.7.0" + "@jest/transform": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + "@types/node": "npm:*" + ansi-escapes: "npm:^4.2.1" + chalk: "npm:^4.0.0" + ci-info: "npm:^3.2.0" + exit: "npm:^0.1.2" + graceful-fs: "npm:^4.2.9" + jest-changed-files: "npm:^29.7.0" + jest-config: "npm:^29.7.0" + jest-haste-map: "npm:^29.7.0" + jest-message-util: "npm:^29.7.0" + jest-regex-util: "npm:^29.6.3" + jest-resolve: "npm:^29.7.0" + jest-resolve-dependencies: "npm:^29.7.0" + jest-runner: "npm:^29.7.0" + jest-runtime: "npm:^29.7.0" + jest-snapshot: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + jest-validate: "npm:^29.7.0" + jest-watcher: "npm:^29.7.0" + micromatch: "npm:^4.0.4" + pretty-format: "npm:^29.7.0" + slash: "npm:^3.0.0" + strip-ansi: "npm:^6.0.0" + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + checksum: 10/ab6ac2e562d083faac7d8152ec1cc4eccc80f62e9579b69ed40aedf7211a6b2d57024a6cd53c4e35fd051c39a236e86257d1d99ebdb122291969a0a04563b51e + languageName: node + linkType: hard + +"@jest/environment@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/environment@npm:29.7.0" + dependencies: + "@jest/fake-timers": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + "@types/node": "npm:*" + jest-mock: "npm:^29.7.0" + checksum: 10/90b5844a9a9d8097f2cf107b1b5e57007c552f64315da8c1f51217eeb0a9664889d3f145cdf8acf23a84f4d8309a6675e27d5b059659a004db0ea9546d1c81a8 + languageName: node + linkType: hard + +"@jest/expect-utils@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/expect-utils@npm:29.7.0" + dependencies: + jest-get-type: "npm:^29.6.3" + checksum: 10/ef8d379778ef574a17bde2801a6f4469f8022a46a5f9e385191dc73bb1fc318996beaed4513fbd7055c2847227a1bed2469977821866534593a6e52a281499ee + languageName: node + linkType: hard + +"@jest/expect@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/expect@npm:29.7.0" + dependencies: + expect: "npm:^29.7.0" + jest-snapshot: "npm:^29.7.0" + checksum: 10/fea6c3317a8da5c840429d90bfe49d928e89c9e89fceee2149b93a11b7e9c73d2f6e4d7cdf647163da938fc4e2169e4490be6bae64952902bc7a701033fd4880 + languageName: node + linkType: hard + +"@jest/fake-timers@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/fake-timers@npm:29.7.0" + dependencies: + "@jest/types": "npm:^29.6.3" + "@sinonjs/fake-timers": "npm:^10.0.2" + "@types/node": "npm:*" + jest-message-util: "npm:^29.7.0" + jest-mock: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + checksum: 10/9b394e04ffc46f91725ecfdff34c4e043eb7a16e1d78964094c9db3fde0b1c8803e45943a980e8c740d0a3d45661906de1416ca5891a538b0660481a3a828c27 + languageName: node + linkType: hard + +"@jest/globals@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/globals@npm:29.7.0" + dependencies: + "@jest/environment": "npm:^29.7.0" + "@jest/expect": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + jest-mock: "npm:^29.7.0" + checksum: 10/97dbb9459135693ad3a422e65ca1c250f03d82b2a77f6207e7fa0edd2c9d2015fbe4346f3dc9ebff1678b9d8da74754d4d440b7837497f8927059c0642a22123 + languageName: node + linkType: hard + +"@jest/reporters@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/reporters@npm:29.7.0" + dependencies: + "@bcoe/v8-coverage": "npm:^0.2.3" + "@jest/console": "npm:^29.7.0" + "@jest/test-result": "npm:^29.7.0" + "@jest/transform": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + "@jridgewell/trace-mapping": "npm:^0.3.18" + "@types/node": "npm:*" + chalk: "npm:^4.0.0" + collect-v8-coverage: "npm:^1.0.0" + exit: "npm:^0.1.2" + glob: "npm:^7.1.3" + graceful-fs: "npm:^4.2.9" + istanbul-lib-coverage: "npm:^3.0.0" + istanbul-lib-instrument: "npm:^6.0.0" + istanbul-lib-report: "npm:^3.0.0" + istanbul-lib-source-maps: "npm:^4.0.0" + istanbul-reports: "npm:^3.1.3" + jest-message-util: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + jest-worker: "npm:^29.7.0" + slash: "npm:^3.0.0" + string-length: "npm:^4.0.1" + strip-ansi: "npm:^6.0.0" + v8-to-istanbul: "npm:^9.0.1" + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + checksum: 10/a17d1644b26dea14445cedd45567f4ba7834f980be2ef74447204e14238f121b50d8b858fde648083d2cd8f305f81ba434ba49e37a5f4237a6f2a61180cc73dc + languageName: node + linkType: hard + +"@jest/schemas@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/schemas@npm:29.6.3" + dependencies: + "@sinclair/typebox": "npm:^0.27.8" + checksum: 10/910040425f0fc93cd13e68c750b7885590b8839066dfa0cd78e7def07bbb708ad869381f725945d66f2284de5663bbecf63e8fdd856e2ae6e261ba30b1687e93 + languageName: node + linkType: hard + +"@jest/source-map@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/source-map@npm:29.6.3" + dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.18" + callsites: "npm:^3.0.0" + graceful-fs: "npm:^4.2.9" + checksum: 10/bcc5a8697d471396c0003b0bfa09722c3cd879ad697eb9c431e6164e2ea7008238a01a07193dfe3cbb48b1d258eb7251f6efcea36f64e1ebc464ea3c03ae2deb + languageName: node + linkType: hard + +"@jest/test-result@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/test-result@npm:29.7.0" + dependencies: + "@jest/console": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + "@types/istanbul-lib-coverage": "npm:^2.0.0" + collect-v8-coverage: "npm:^1.0.0" + checksum: 10/c073ab7dfe3c562bff2b8fee6cc724ccc20aa96bcd8ab48ccb2aa309b4c0c1923a9e703cea386bd6ae9b71133e92810475bb9c7c22328fc63f797ad3324ed189 + languageName: node + linkType: hard + +"@jest/test-sequencer@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/test-sequencer@npm:29.7.0" + dependencies: + "@jest/test-result": "npm:^29.7.0" + graceful-fs: "npm:^4.2.9" + jest-haste-map: "npm:^29.7.0" + slash: "npm:^3.0.0" + checksum: 10/4420c26a0baa7035c5419b0892ff8ffe9a41b1583ec54a10db3037cd46a7e29dd3d7202f8aa9d376e9e53be5f8b1bc0d16e1de6880a6d319b033b01dc4c8f639 + languageName: node + linkType: hard + +"@jest/transform@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/transform@npm:29.7.0" + dependencies: + "@babel/core": "npm:^7.11.6" + "@jest/types": "npm:^29.6.3" + "@jridgewell/trace-mapping": "npm:^0.3.18" + babel-plugin-istanbul: "npm:^6.1.1" + chalk: "npm:^4.0.0" + convert-source-map: "npm:^2.0.0" + fast-json-stable-stringify: "npm:^2.1.0" + graceful-fs: "npm:^4.2.9" + jest-haste-map: "npm:^29.7.0" + jest-regex-util: "npm:^29.6.3" + jest-util: "npm:^29.7.0" + micromatch: "npm:^4.0.4" + pirates: "npm:^4.0.4" + slash: "npm:^3.0.0" + write-file-atomic: "npm:^4.0.2" + checksum: 10/30f42293545ab037d5799c81d3e12515790bb58513d37f788ce32d53326d0d72ebf5b40f989e6896739aa50a5f77be44686e510966370d58511d5ad2637c68c1 + languageName: node + linkType: hard + +"@jest/types@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/types@npm:29.6.3" + dependencies: + "@jest/schemas": "npm:^29.6.3" + "@types/istanbul-lib-coverage": "npm:^2.0.0" + "@types/istanbul-reports": "npm:^3.0.0" + "@types/node": "npm:*" + "@types/yargs": "npm:^17.0.8" + chalk: "npm:^4.0.0" + checksum: 10/f74bf512fd09bbe2433a2ad460b04668b7075235eea9a0c77d6a42222c10a79b9747dc2b2a623f140ed40d6865a2ed8f538f3cbb75169120ea863f29a7ed76cd + languageName: node + linkType: hard + +"@jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.8 + resolution: "@jridgewell/gen-mapping@npm:0.3.8" + dependencies: + "@jridgewell/set-array": "npm:^1.2.1" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10/9d3a56ab3612ab9b85d38b2a93b87f3324f11c5130859957f6500e4ac8ce35f299d5ccc3ecd1ae87597601ecf83cee29e9afd04c18777c24011073992ff946df + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.2 resolution: "@jridgewell/resolve-uri@npm:3.1.2" checksum: 10/97106439d750a409c22c8bff822d648f6a71f3aa9bc8e5129efdc36343cd3096ddc4eeb1c62d2fe48e9bdd4db37b05d4646a17114ecebd3bbcacfa2de51c3c1d languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.5.0": +"@jridgewell/set-array@npm:^1.2.1": + version: 1.2.1 + resolution: "@jridgewell/set-array@npm:1.2.1" + checksum: 10/832e513a85a588f8ed4f27d1279420d8547743cc37fcad5a5a76fc74bb895b013dfe614d0eed9cb860048e6546b798f8f2652020b4b2ba0561b05caa8c654b10 + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": version: 1.5.0 resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" checksum: 10/4ed6123217569a1484419ac53f6ea0d9f3b57e5b57ab30d7c267bdb27792a27eb0e4b08e84a2680aa55cc2f2b411ffd6ec3db01c44fdc6dc43aca4b55f8374fd @@ -327,6 +974,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": + version: 0.3.25 + resolution: "@jridgewell/trace-mapping@npm:0.3.25" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10/dced32160a44b49d531b80a4a2159dceab6b3ddf0c8e95a0deae4b0e894b172defa63d5ac52a19c2068e1fe7d31ea4ba931fbeec103233ecb4208953967120fc + languageName: node + linkType: hard + "@midnight-ntwrk/compact-runtime@npm:^0.8.1": version: 0.8.1 resolution: "@midnight-ntwrk/compact-runtime@npm:0.8.1" @@ -596,6 +1253,31 @@ __metadata: languageName: node linkType: hard +"@sinclair/typebox@npm:^0.27.8": + version: 0.27.8 + resolution: "@sinclair/typebox@npm:0.27.8" + checksum: 10/297f95ff77c82c54de8c9907f186076e715ff2621c5222ba50b8d40a170661c0c5242c763cba2a4791f0f91cb1d8ffa53ea1d7294570cf8cd4694c0e383e484d + languageName: node + linkType: hard + +"@sinonjs/commons@npm:^3.0.0": + version: 3.0.1 + resolution: "@sinonjs/commons@npm:3.0.1" + dependencies: + type-detect: "npm:4.0.8" + checksum: 10/a0af217ba7044426c78df52c23cedede6daf377586f3ac58857c565769358ab1f44ebf95ba04bbe38814fba6e316ca6f02870a009328294fc2c555d0f85a7117 + languageName: node + linkType: hard + +"@sinonjs/fake-timers@npm:^10.0.2": + version: 10.3.0 + resolution: "@sinonjs/fake-timers@npm:10.3.0" + dependencies: + "@sinonjs/commons": "npm:^3.0.0" + checksum: 10/78155c7bd866a85df85e22028e046b8d46cf3e840f72260954f5e3ed5bd97d66c595524305a6841ffb3f681a08f6e5cef572a2cce5442a8a232dc29fb409b83e + languageName: node + linkType: hard + "@tsconfig/node10@npm:^1.0.7": version: 1.0.11 resolution: "@tsconfig/node10@npm:1.0.11" @@ -624,19 +1306,113 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:1.0.7, @types/estree@npm:^1.0.0": - version: 1.0.7 - resolution: "@types/estree@npm:1.0.7" - checksum: 10/419c845ece767ad4b21171e6e5b63dabb2eb46b9c0d97361edcd9cabbf6a95fcadb91d89b5fa098d1336fa0b8fceaea82fca97a2ef3971f5c86e53031e157b21 +"@types/babel__core@npm:^7.1.14": + version: 7.20.5 + resolution: "@types/babel__core@npm:7.20.5" + dependencies: + "@babel/parser": "npm:^7.20.7" + "@babel/types": "npm:^7.20.7" + "@types/babel__generator": "npm:*" + "@types/babel__template": "npm:*" + "@types/babel__traverse": "npm:*" + checksum: 10/c32838d280b5ab59d62557f9e331d3831f8e547ee10b4f85cb78753d97d521270cebfc73ce501e9fb27fe71884d1ba75e18658692c2f4117543f0fc4e3e118b3 languageName: node linkType: hard -"@types/node@npm:^18.18.6": - version: 18.19.87 - resolution: "@types/node@npm:18.19.87" +"@types/babel__generator@npm:*": + version: 7.27.0 + resolution: "@types/babel__generator@npm:7.27.0" dependencies: - undici-types: "npm:~5.26.4" - checksum: 10/1e71b6d16dedeaa1fd5ff55baf1f353ca1f9e673b2e482d7fe82fa685addea5159a36602a344784c989b5e07ca1be633d0c493adf5951dee5a29cee69d613e7f + "@babel/types": "npm:^7.0.0" + checksum: 10/f572e67a9a39397664350a4437d8a7fbd34acc83ff4887a8cf08349e39f8aeb5ad2f70fb78a0a0a23a280affe3a5f4c25f50966abdce292bcf31237af1c27b1a + languageName: node + linkType: hard + +"@types/babel__template@npm:*": + version: 7.4.4 + resolution: "@types/babel__template@npm:7.4.4" + dependencies: + "@babel/parser": "npm:^7.1.0" + "@babel/types": "npm:^7.0.0" + checksum: 10/d7a02d2a9b67e822694d8e6a7ddb8f2b71a1d6962dfd266554d2513eefbb205b33ca71a0d163b1caea3981ccf849211f9964d8bd0727124d18ace45aa6c9ae29 + languageName: node + linkType: hard + +"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6": + version: 7.20.7 + resolution: "@types/babel__traverse@npm:7.20.7" + dependencies: + "@babel/types": "npm:^7.20.7" + checksum: 10/d005b58e1c26bdafc1ce564f60db0ee938393c7fc586b1197bdb71a02f7f33f72bc10ae4165776b6cafc77c4b6f2e1a164dd20bc36518c471b1131b153b4baa6 + languageName: node + linkType: hard + +"@types/estree@npm:1.0.7, @types/estree@npm:^1.0.0": + version: 1.0.7 + resolution: "@types/estree@npm:1.0.7" + checksum: 10/419c845ece767ad4b21171e6e5b63dabb2eb46b9c0d97361edcd9cabbf6a95fcadb91d89b5fa098d1336fa0b8fceaea82fca97a2ef3971f5c86e53031e157b21 + languageName: node + linkType: hard + +"@types/graceful-fs@npm:^4.1.3": + version: 4.1.9 + resolution: "@types/graceful-fs@npm:4.1.9" + dependencies: + "@types/node": "npm:*" + checksum: 10/79d746a8f053954bba36bd3d94a90c78de995d126289d656fb3271dd9f1229d33f678da04d10bce6be440494a5a73438e2e363e92802d16b8315b051036c5256 + languageName: node + linkType: hard + +"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": + version: 2.0.6 + resolution: "@types/istanbul-lib-coverage@npm:2.0.6" + checksum: 10/3feac423fd3e5449485afac999dcfcb3d44a37c830af898b689fadc65d26526460bedb889db278e0d4d815a670331796494d073a10ee6e3a6526301fe7415778 + languageName: node + linkType: hard + +"@types/istanbul-lib-report@npm:*": + version: 3.0.3 + resolution: "@types/istanbul-lib-report@npm:3.0.3" + dependencies: + "@types/istanbul-lib-coverage": "npm:*" + checksum: 10/b91e9b60f865ff08cb35667a427b70f6c2c63e88105eadd29a112582942af47ed99c60610180aa8dcc22382fa405033f141c119c69b95db78c4c709fbadfeeb4 + languageName: node + linkType: hard + +"@types/istanbul-reports@npm:^3.0.0": + version: 3.0.4 + resolution: "@types/istanbul-reports@npm:3.0.4" + dependencies: + "@types/istanbul-lib-report": "npm:*" + checksum: 10/93eb18835770b3431f68ae9ac1ca91741ab85f7606f310a34b3586b5a34450ec038c3eed7ab19266635499594de52ff73723a54a72a75b9f7d6a956f01edee95 + languageName: node + linkType: hard + +"@types/jest@npm:^29.5.6": + version: 29.5.14 + resolution: "@types/jest@npm:29.5.14" + dependencies: + expect: "npm:^29.0.0" + pretty-format: "npm:^29.0.0" + checksum: 10/59ec7a9c4688aae8ee529316c43853468b6034f453d08a2e1064b281af9c81234cec986be796288f1bbb29efe943bc950e70c8fa8faae1e460d50e3cf9760f9b + languageName: node + linkType: hard + +"@types/node@npm:*": + version: 22.15.19 + resolution: "@types/node@npm:22.15.19" + dependencies: + undici-types: "npm:~6.21.0" + checksum: 10/02311c2b5dbf2e9e2c17497dc27858bcefbe12a81af0d9b81f865613d8d014726e0eb6cbebfbdb84a327c1b9f9da1347a65a7699ac58c8854fb4daf447031149 + languageName: node + linkType: hard + +"@types/node@npm:^18.18.6": + version: 18.19.87 + resolution: "@types/node@npm:18.19.87" + dependencies: + undici-types: "npm:~5.26.4" + checksum: 10/1e71b6d16dedeaa1fd5ff55baf1f353ca1f9e673b2e482d7fe82fa685addea5159a36602a344784c989b5e07ca1be633d0c493adf5951dee5a29cee69d613e7f languageName: node linkType: hard @@ -665,6 +1441,29 @@ __metadata: languageName: node linkType: hard +"@types/stack-utils@npm:^2.0.0": + version: 2.0.3 + resolution: "@types/stack-utils@npm:2.0.3" + checksum: 10/72576cc1522090fe497337c2b99d9838e320659ac57fa5560fcbdcbafcf5d0216c6b3a0a8a4ee4fdb3b1f5e3420aa4f6223ab57b82fef3578bec3206425c6cf5 + languageName: node + linkType: hard + +"@types/yargs-parser@npm:*": + version: 21.0.3 + resolution: "@types/yargs-parser@npm:21.0.3" + checksum: 10/a794eb750e8ebc6273a51b12a0002de41343ffe46befef460bdbb57262d187fdf608bc6615b7b11c462c63c3ceb70abe2564c8dd8ee0f7628f38a314f74a9b9b + languageName: node + linkType: hard + +"@types/yargs@npm:^17.0.8": + version: 17.0.33 + resolution: "@types/yargs@npm:17.0.33" + dependencies: + "@types/yargs-parser": "npm:*" + checksum: 10/16f6681bf4d99fb671bf56029141ed01db2862e3db9df7fc92d8bea494359ac96a1b4b1c35a836d1e95e665fb18ad753ab2015fc0db663454e8fd4e5d5e2ef91 + languageName: node + linkType: hard + "@vitest/expect@npm:3.1.3": version: 3.1.3 resolution: "@vitest/expect@npm:3.1.3" @@ -778,6 +1577,15 @@ __metadata: languageName: node linkType: hard +"ansi-escapes@npm:^4.2.1": + version: 4.3.2 + resolution: "ansi-escapes@npm:4.3.2" + dependencies: + type-fest: "npm:^0.21.3" + checksum: 10/8661034456193ffeda0c15c8c564a9636b0c04094b7f78bd01517929c17c504090a60f7a75f949f5af91289c264d3e1001d91492c1bd58efc8e100500ce04de2 + languageName: node + linkType: hard + "ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" @@ -792,7 +1600,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^4.0.0": +"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: @@ -801,6 +1609,13 @@ __metadata: languageName: node linkType: hard +"ansi-styles@npm:^5.0.0": + version: 5.2.0 + resolution: "ansi-styles@npm:5.2.0" + checksum: 10/d7f4e97ce0623aea6bc0d90dcd28881ee04cba06c570b97fd3391bd7a268eedfd9d5e2dd4fdcbdd82b8105df5faf6f24aaedc08eaf3da898e702db5948f63469 + languageName: node + linkType: hard + "ansi-styles@npm:^6.1.0": version: 6.2.1 resolution: "ansi-styles@npm:6.2.1" @@ -808,6 +1623,16 @@ __metadata: languageName: node linkType: hard +"anymatch@npm:^3.0.3": + version: 3.1.3 + resolution: "anymatch@npm:3.1.3" + dependencies: + normalize-path: "npm:^3.0.0" + picomatch: "npm:^2.0.4" + checksum: 10/3e044fd6d1d26545f235a9fe4d7a534e2029d8e59fa7fd9f2a6eb21230f6b5380ea1eaf55136e60cbf8e613544b3b766e7a6fa2102e2a3a117505466e3025dc2 + languageName: node + linkType: hard + "arg@npm:^4.1.0": version: 4.1.3 resolution: "arg@npm:4.1.3" @@ -815,6 +1640,15 @@ __metadata: languageName: node linkType: hard +"argparse@npm:^1.0.7": + version: 1.0.10 + resolution: "argparse@npm:1.0.10" + dependencies: + sprintf-js: "npm:~1.0.2" + checksum: 10/c6a621343a553ff3779390bb5ee9c2263d6643ebcd7843227bdde6cc7adbed796eb5540ca98db19e3fd7b4714e1faa51551f8849b268bb62df27ddb15cbcd91e + languageName: node + linkType: hard + "assertion-error@npm:^2.0.1": version: 2.0.1 resolution: "assertion-error@npm:2.0.1" @@ -822,6 +1656,85 @@ __metadata: languageName: node linkType: hard +"babel-jest@npm:^29.7.0": + version: 29.7.0 + resolution: "babel-jest@npm:29.7.0" + dependencies: + "@jest/transform": "npm:^29.7.0" + "@types/babel__core": "npm:^7.1.14" + babel-plugin-istanbul: "npm:^6.1.1" + babel-preset-jest: "npm:^29.6.3" + chalk: "npm:^4.0.0" + graceful-fs: "npm:^4.2.9" + slash: "npm:^3.0.0" + peerDependencies: + "@babel/core": ^7.8.0 + checksum: 10/8a0953bd813b3a8926008f7351611055548869e9a53dd36d6e7e96679001f71e65fd7dbfe253265c3ba6a4e630dc7c845cf3e78b17d758ef1880313ce8fba258 + languageName: node + linkType: hard + +"babel-plugin-istanbul@npm:^6.1.1": + version: 6.1.1 + resolution: "babel-plugin-istanbul@npm:6.1.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.0.0" + "@istanbuljs/load-nyc-config": "npm:^1.0.0" + "@istanbuljs/schema": "npm:^0.1.2" + istanbul-lib-instrument: "npm:^5.0.4" + test-exclude: "npm:^6.0.0" + checksum: 10/ffd436bb2a77bbe1942a33245d770506ab2262d9c1b3c1f1da7f0592f78ee7445a95bc2efafe619dd9c1b6ee52c10033d6c7d29ddefe6f5383568e60f31dfe8d + languageName: node + linkType: hard + +"babel-plugin-jest-hoist@npm:^29.6.3": + version: 29.6.3 + resolution: "babel-plugin-jest-hoist@npm:29.6.3" + dependencies: + "@babel/template": "npm:^7.3.3" + "@babel/types": "npm:^7.3.3" + "@types/babel__core": "npm:^7.1.14" + "@types/babel__traverse": "npm:^7.0.6" + checksum: 10/9bfa86ec4170bd805ab8ca5001ae50d8afcb30554d236ba4a7ffc156c1a92452e220e4acbd98daefc12bf0216fccd092d0a2efed49e7e384ec59e0597a926d65 + languageName: node + linkType: hard + +"babel-preset-current-node-syntax@npm:^1.0.0": + version: 1.1.0 + resolution: "babel-preset-current-node-syntax@npm:1.1.0" + dependencies: + "@babel/plugin-syntax-async-generators": "npm:^7.8.4" + "@babel/plugin-syntax-bigint": "npm:^7.8.3" + "@babel/plugin-syntax-class-properties": "npm:^7.12.13" + "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" + "@babel/plugin-syntax-import-attributes": "npm:^7.24.7" + "@babel/plugin-syntax-import-meta": "npm:^7.10.4" + "@babel/plugin-syntax-json-strings": "npm:^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" + "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" + "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" + "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" + "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" + "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" + "@babel/plugin-syntax-top-level-await": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/46331111ae72b7121172fd9e6a4a7830f651ad44bf26dbbf77b3c8a60a18009411a3eacb5e72274004290c110371230272109957d5224d155436b4794ead2f1b + languageName: node + linkType: hard + +"babel-preset-jest@npm:^29.6.3": + version: 29.6.3 + resolution: "babel-preset-jest@npm:29.6.3" + dependencies: + babel-plugin-jest-hoist: "npm:^29.6.3" + babel-preset-current-node-syntax: "npm:^1.0.0" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/aa4ff2a8a728d9d698ed521e3461a109a1e66202b13d3494e41eea30729a5e7cc03b3a2d56c594423a135429c37bf63a9fa8b0b9ce275298be3095a88c69f6fb + languageName: node + linkType: hard + "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -829,6 +1742,16 @@ __metadata: languageName: node linkType: hard +"brace-expansion@npm:^1.1.7": + version: 1.1.11 + resolution: "brace-expansion@npm:1.1.11" + dependencies: + balanced-match: "npm:^1.0.0" + concat-map: "npm:0.0.1" + checksum: 10/faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 + languageName: node + linkType: hard + "brace-expansion@npm:^2.0.1": version: 2.0.1 resolution: "brace-expansion@npm:2.0.1" @@ -838,6 +1761,45 @@ __metadata: languageName: node linkType: hard +"braces@npm:^3.0.3": + version: 3.0.3 + resolution: "braces@npm:3.0.3" + dependencies: + fill-range: "npm:^7.1.1" + checksum: 10/fad11a0d4697a27162840b02b1fad249c1683cbc510cd5bf1a471f2f8085c046d41094308c577a50a03a579dd99d5a6b3724c4b5e8b14df2c4443844cfcda2c6 + languageName: node + linkType: hard + +"browserslist@npm:^4.24.0": + version: 4.24.5 + resolution: "browserslist@npm:4.24.5" + dependencies: + caniuse-lite: "npm:^1.0.30001716" + electron-to-chromium: "npm:^1.5.149" + node-releases: "npm:^2.0.19" + update-browserslist-db: "npm:^1.1.3" + bin: + browserslist: cli.js + checksum: 10/93fde829b77f20e2c4e1e0eaed154681c05e4828420e4afba790d480daa5de742977a44bbac8567881b8fbec3da3dea7ca1cb578ac1fd4385ef4ae91ca691d64 + languageName: node + linkType: hard + +"bser@npm:2.1.1": + version: 2.1.1 + resolution: "bser@npm:2.1.1" + dependencies: + node-int64: "npm:^0.4.0" + checksum: 10/edba1b65bae682450be4117b695997972bd9a3c4dfee029cab5bcb72ae5393a79a8f909b8bc77957eb0deec1c7168670f18f4d5c556f46cdd3bca5f3b3a8d020 + languageName: node + linkType: hard + +"buffer-from@npm:^1.0.0": + version: 1.1.2 + resolution: "buffer-from@npm:1.1.2" + checksum: 10/0448524a562b37d4d7ed9efd91685a5b77a50672c556ea254ac9a6d30e3403a517d8981f10e565db24e8339413b43c97ca2951f10e399c6125a0d8911f5679bb + languageName: node + linkType: hard + "cac@npm:^6.7.14": version: 6.7.14 resolution: "cac@npm:6.7.14" @@ -865,6 +1827,34 @@ __metadata: languageName: node linkType: hard +"callsites@npm:^3.0.0": + version: 3.1.0 + resolution: "callsites@npm:3.1.0" + checksum: 10/072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 + languageName: node + linkType: hard + +"camelcase@npm:^5.3.1": + version: 5.3.1 + resolution: "camelcase@npm:5.3.1" + checksum: 10/e6effce26b9404e3c0f301498184f243811c30dfe6d0b9051863bd8e4034d09c8c2923794f280d6827e5aa055f6c434115ff97864a16a963366fb35fd673024b + languageName: node + linkType: hard + +"camelcase@npm:^6.2.0": + version: 6.3.0 + resolution: "camelcase@npm:6.3.0" + checksum: 10/8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001716": + version: 1.0.30001718 + resolution: "caniuse-lite@npm:1.0.30001718" + checksum: 10/e172a4c156f743cc947e659f353ad9edb045725cc109a02cc792dcbf98569356ebfa4bb4356e3febf87427aab0951c34c1ee5630629334f25ae6f76de7d86fd0 + languageName: node + linkType: hard + "chai@npm:^5.2.0": version: 5.2.0 resolution: "chai@npm:5.2.0" @@ -878,6 +1868,16 @@ __metadata: languageName: node linkType: hard +"chalk@npm:^4.0.0": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: "npm:^4.1.0" + supports-color: "npm:^7.1.0" + checksum: 10/cb3f3e594913d63b1814d7ca7c9bafbf895f75fbf93b92991980610dfd7b48500af4e3a5d4e3a8f337990a96b168d7eb84ee55efdce965e2ee8efc20f8c8f139 + languageName: node + linkType: hard + "chalk@npm:^5.3.0, chalk@npm:^5.4.1": version: 5.4.1 resolution: "chalk@npm:5.4.1" @@ -885,6 +1885,13 @@ __metadata: languageName: node linkType: hard +"char-regex@npm:^1.0.2": + version: 1.0.2 + resolution: "char-regex@npm:1.0.2" + checksum: 10/1ec5c2906adb9f84e7f6732a40baef05d7c85401b82ffcbc44b85fbd0f7a2b0c2a96f2eb9cf55cae3235dc12d4023003b88f09bcae8be9ae894f52ed746f4d48 + languageName: node + linkType: hard + "check-error@npm:^2.1.1": version: 2.1.1 resolution: "check-error@npm:2.1.1" @@ -899,6 +1906,20 @@ __metadata: languageName: node linkType: hard +"ci-info@npm:^3.2.0": + version: 3.9.0 + resolution: "ci-info@npm:3.9.0" + checksum: 10/75bc67902b4d1c7b435497adeb91598f6d52a3389398e44294f6601b20cfef32cf2176f7be0eb961d9e085bb333a8a5cae121cb22f81cf238ae7f58eb80e9397 + languageName: node + linkType: hard + +"cjs-module-lexer@npm:^1.0.0": + version: 1.4.3 + resolution: "cjs-module-lexer@npm:1.4.3" + checksum: 10/d2b92f919a2dedbfd61d016964fce8da0035f827182ed6839c97cac56e8a8077cfa6a59388adfe2bc588a19cef9bbe830d683a76a6e93c51f65852062cfe2591 + languageName: node + linkType: hard + "cli-cursor@npm:^5.0.0": version: 5.0.0 resolution: "cli-cursor@npm:5.0.0" @@ -915,6 +1936,31 @@ __metadata: languageName: node linkType: hard +"cliui@npm:^8.0.1": + version: 8.0.1 + resolution: "cliui@npm:8.0.1" + dependencies: + string-width: "npm:^4.2.0" + strip-ansi: "npm:^6.0.1" + wrap-ansi: "npm:^7.0.0" + checksum: 10/eaa5561aeb3135c2cddf7a3b3f562fc4238ff3b3fc666869ef2adf264be0f372136702f16add9299087fb1907c2e4ec5dbfe83bd24bce815c70a80c6c1a2e950 + languageName: node + linkType: hard + +"co@npm:^4.6.0": + version: 4.6.0 + resolution: "co@npm:4.6.0" + checksum: 10/a5d9f37091c70398a269e625cedff5622f200ed0aa0cff22ee7b55ed74a123834b58711776eb0f1dc58eb6ebbc1185aa7567b57bd5979a948c6e4f85073e2c05 + languageName: node + linkType: hard + +"collect-v8-coverage@npm:^1.0.0": + version: 1.0.2 + resolution: "collect-v8-coverage@npm:1.0.2" + checksum: 10/30ea7d5c9ee51f2fdba4901d4186c5b7114a088ef98fd53eda3979da77eed96758a2cae81cc6d97e239aaea6065868cf908b24980663f7b7e96aa291b3e12fa4 + languageName: node + linkType: hard + "color-convert@npm:^2.0.1": version: 2.0.1 resolution: "color-convert@npm:2.0.1" @@ -931,6 +1977,37 @@ __metadata: languageName: node linkType: hard +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 10/9680699c8e2b3af0ae22592cb764acaf973f292a7b71b8a06720233011853a58e256c89216a10cbe889727532fd77f8bcd49a760cedfde271b8e006c20e079f2 + languageName: node + linkType: hard + +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: 10/c987be3ec061348cdb3c2bfb924bec86dea1eacad10550a85ca23edb0fe3556c3a61c7399114f3331ccb3499d7fd0285ab24566e5745929412983494c3926e15 + languageName: node + linkType: hard + +"create-jest@npm:^29.7.0": + version: 29.7.0 + resolution: "create-jest@npm:29.7.0" + dependencies: + "@jest/types": "npm:^29.6.3" + chalk: "npm:^4.0.0" + exit: "npm:^0.1.2" + graceful-fs: "npm:^4.2.9" + jest-config: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + prompts: "npm:^2.0.1" + bin: + create-jest: bin/create-jest.js + checksum: 10/847b4764451672b4174be4d5c6d7d63442ec3aa5f3de52af924e4d996d87d7801c18e125504f25232fc75840f6625b3ac85860fac6ce799b5efae7bdcaf4a2b7 + languageName: node + linkType: hard + "create-require@npm:^1.1.0": version: 1.1.1 resolution: "create-require@npm:1.1.1" @@ -938,7 +2015,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.6": +"cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -949,7 +2026,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.3.4, debug@npm:^4.4.0": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.4, debug@npm:^4.4.0": version: 4.4.1 resolution: "debug@npm:4.4.1" dependencies: @@ -961,6 +2038,18 @@ __metadata: languageName: node linkType: hard +"dedent@npm:^1.0.0": + version: 1.6.0 + resolution: "dedent@npm:1.6.0" + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + checksum: 10/f100cb11001309f2185c4334c6f29e5323c1e73b7b75e3b1893bc71ef53cd13fb80534efc8fa7163a891ede633e310a9c600ba38c363cc9d14a72f238fe47078 + languageName: node + linkType: hard + "deep-eql@npm:^5.0.1": version: 5.0.2 resolution: "deep-eql@npm:5.0.2" @@ -968,6 +2057,27 @@ __metadata: languageName: node linkType: hard +"deepmerge@npm:^4.2.2": + version: 4.3.1 + resolution: "deepmerge@npm:4.3.1" + checksum: 10/058d9e1b0ff1a154468bf3837aea436abcfea1ba1d165ddaaf48ca93765fdd01a30d33c36173da8fbbed951dd0a267602bc782fe288b0fc4b7e1e7091afc4529 + languageName: node + linkType: hard + +"detect-newline@npm:^3.0.0": + version: 3.1.0 + resolution: "detect-newline@npm:3.1.0" + checksum: 10/ae6cd429c41ad01b164c59ea36f264a2c479598e61cba7c99da24175a7ab80ddf066420f2bec9a1c57a6bead411b4655ff15ad7d281c000a89791f48cbe939e7 + languageName: node + linkType: hard + +"diff-sequences@npm:^29.6.3": + version: 29.6.3 + resolution: "diff-sequences@npm:29.6.3" + checksum: 10/179daf9d2f9af5c57ad66d97cb902a538bcf8ed64963fa7aa0c329b3de3665ce2eb6ffdc2f69f29d445fa4af2517e5e55e5b6e00c00a9ae4f43645f97f7078cb + languageName: node + linkType: hard + "diff@npm:^4.0.1": version: 4.0.2 resolution: "diff@npm:4.0.2" @@ -982,6 +2092,20 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.5.149": + version: 1.5.155 + resolution: "electron-to-chromium@npm:1.5.155" + checksum: 10/3c3fff052b8cdf18edca56b45ed1d52f665c943e6ef5c09cb33b2d06b774d705cc7679ea886bdde35b0ebafe30d6f570223fcfc7b687d7c0c34286368d7f4976 + languageName: node + linkType: hard + +"emittery@npm:^0.13.1": + version: 0.13.1 + resolution: "emittery@npm:0.13.1" + checksum: 10/fbe214171d878b924eedf1757badf58a5dce071cd1fa7f620fa841a0901a80d6da47ff05929d53163105e621ce11a71b9d8acb1148ffe1745e045145f6e69521 + languageName: node + linkType: hard + "emoji-regex@npm:^10.3.0": version: 10.4.0 resolution: "emoji-regex@npm:10.4.0" @@ -1026,6 +2150,15 @@ __metadata: languageName: node linkType: hard +"error-ex@npm:^1.3.1": + version: 1.3.2 + resolution: "error-ex@npm:1.3.2" + dependencies: + is-arrayish: "npm:^0.2.1" + checksum: 10/d547740aa29c34e753fb6fed2c5de81802438529c12b3673bd37b6bb1fe49b9b7abdc3c11e6062fe625d8a296b3cf769a80f878865e25e685f787763eede3ffb + languageName: node + linkType: hard + "es-module-lexer@npm:^1.7.0": version: 1.7.0 resolution: "es-module-lexer@npm:1.7.0" @@ -1119,6 +2252,30 @@ __metadata: languageName: node linkType: hard +"escalade@npm:^3.1.1, escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10/9d7169e3965b2f9ae46971afa392f6e5a25545ea30f2e2dd99c9b0a95a3f52b5653681a84f5b2911a413ddad2d7a93d3514165072f349b5ffc59c75a899970d6 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^2.0.0": + version: 2.0.0 + resolution: "escape-string-regexp@npm:2.0.0" + checksum: 10/9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 + languageName: node + linkType: hard + +"esprima@npm:^4.0.0": + version: 4.0.1 + resolution: "esprima@npm:4.0.1" + bin: + esparse: ./bin/esparse.js + esvalidate: ./bin/esvalidate.js + checksum: 10/f1d3c622ad992421362294f7acf866aa9409fbad4eb2e8fa230bd33944ce371d32279667b242d8b8907ec2b6ad7353a717f3c0e60e748873a34a7905174bc0eb + languageName: node + linkType: hard + "estree-walker@npm:^3.0.3": version: 3.0.3 resolution: "estree-walker@npm:3.0.3" @@ -1128,6 +2285,30 @@ __metadata: languageName: node linkType: hard +"execa@npm:^5.0.0": + version: 5.1.1 + resolution: "execa@npm:5.1.1" + dependencies: + cross-spawn: "npm:^7.0.3" + get-stream: "npm:^6.0.0" + human-signals: "npm:^2.1.0" + is-stream: "npm:^2.0.0" + merge-stream: "npm:^2.0.0" + npm-run-path: "npm:^4.0.1" + onetime: "npm:^5.1.2" + signal-exit: "npm:^3.0.3" + strip-final-newline: "npm:^2.0.0" + checksum: 10/8ada91f2d70f7dff702c861c2c64f21dfdc1525628f3c0454fd6f02fce65f7b958616cbd2b99ca7fa4d474e461a3d363824e91b3eb881705231abbf387470597 + languageName: node + linkType: hard + +"exit@npm:^0.1.2": + version: 0.1.2 + resolution: "exit@npm:0.1.2" + checksum: 10/387555050c5b3c10e7a9e8df5f43194e95d7737c74532c409910e585d5554eaff34960c166643f5e23d042196529daad059c292dcf1fb61b8ca878d3677f4b87 + languageName: node + linkType: hard + "expect-type@npm:^1.2.1": version: 1.2.1 resolution: "expect-type@npm:1.2.1" @@ -1135,6 +2316,19 @@ __metadata: languageName: node linkType: hard +"expect@npm:^29.0.0, expect@npm:^29.7.0": + version: 29.7.0 + resolution: "expect@npm:29.7.0" + dependencies: + "@jest/expect-utils": "npm:^29.7.0" + jest-get-type: "npm:^29.6.3" + jest-matcher-utils: "npm:^29.7.0" + jest-message-util: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + checksum: 10/63f97bc51f56a491950fb525f9ad94f1916e8a014947f8d8445d3847a665b5471b768522d659f5e865db20b6c2033d2ac10f35fcbd881a4d26407a4f6f18451a + languageName: node + linkType: hard + "exponential-backoff@npm:^3.1.1": version: 3.1.2 resolution: "exponential-backoff@npm:3.1.2" @@ -1151,6 +2345,22 @@ __metadata: languageName: node linkType: hard +"fast-json-stable-stringify@npm:^2.1.0": + version: 2.1.0 + resolution: "fast-json-stable-stringify@npm:2.1.0" + checksum: 10/2c20055c1fa43c922428f16ca8bb29f2807de63e5c851f665f7ac9790176c01c3b40335257736b299764a8d383388dabc73c8083b8e1bc3d99f0a941444ec60e + languageName: node + linkType: hard + +"fb-watchman@npm:^2.0.0": + version: 2.0.2 + resolution: "fb-watchman@npm:2.0.2" + dependencies: + bser: "npm:2.1.1" + checksum: 10/4f95d336fb805786759e383fd7fff342ceb7680f53efcc0ef82f502eb479ce35b98e8b207b6dfdfeea0eba845862107dc73813775fc6b56b3098c6e90a2dad77 + languageName: node + linkType: hard + "fdir@npm:^6.4.4": version: 6.4.4 resolution: "fdir@npm:6.4.4" @@ -1163,6 +2373,25 @@ __metadata: languageName: node linkType: hard +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" + dependencies: + to-regex-range: "npm:^5.0.1" + checksum: 10/a7095cb39e5bc32fada2aa7c7249d3f6b01bd1ce461a61b0adabacccabd9198500c6fb1f68a7c851a657e273fce2233ba869638897f3d7ed2e87a2d89b4436ea + languageName: node + linkType: hard + +"find-up@npm:^4.0.0, find-up@npm:^4.1.0": + version: 4.1.0 + resolution: "find-up@npm:4.1.0" + dependencies: + locate-path: "npm:^5.0.0" + path-exists: "npm:^4.0.0" + checksum: 10/4c172680e8f8c1f78839486e14a43ef82e9decd0e74145f40707cc42e7420506d5ec92d9a11c22bd2c48fb0c384ea05dd30e10dd152fefeec6f2f75282a8b844 + languageName: node + linkType: hard + "foreground-child@npm:^3.1.0": version: 3.3.1 resolution: "foreground-child@npm:3.3.1" @@ -1182,7 +2411,14 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": +"fs.realpath@npm:^1.0.0": + version: 1.0.0 + resolution: "fs.realpath@npm:1.0.0" + checksum: 10/e703107c28e362d8d7b910bbcbfd371e640a3bb45ae157a362b5952c0030c0b6d4981140ec319b347bce7adc025dd7813da1ff908a945ac214d64f5402a51b96 + languageName: node + linkType: hard + +"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" dependencies: @@ -1192,7 +2428,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": +"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" dependencies: @@ -1201,6 +2437,27 @@ __metadata: languageName: node linkType: hard +"function-bind@npm:^1.1.2": + version: 1.1.2 + resolution: "function-bind@npm:1.1.2" + checksum: 10/185e20d20f10c8d661d59aac0f3b63b31132d492e1b11fcc2a93cb2c47257ebaee7407c38513efd2b35cafdf972d9beb2ea4593c1e0f3bf8f2744836928d7454 + languageName: node + linkType: hard + +"gensync@npm:^1.0.0-beta.2": + version: 1.0.0-beta.2 + resolution: "gensync@npm:1.0.0-beta.2" + checksum: 10/17d8333460204fbf1f9160d067e1e77f908a5447febb49424b8ab043026049835c9ef3974445c57dbd39161f4d2b04356d7de12b2eecaa27a7a7ea7d871cbedd + languageName: node + linkType: hard + +"get-caller-file@npm:^2.0.5": + version: 2.0.5 + resolution: "get-caller-file@npm:2.0.5" + checksum: 10/b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9 + languageName: node + linkType: hard + "get-east-asian-width@npm:^1.0.0": version: 1.3.0 resolution: "get-east-asian-width@npm:1.3.0" @@ -1208,6 +2465,20 @@ __metadata: languageName: node linkType: hard +"get-package-type@npm:^0.1.0": + version: 0.1.0 + resolution: "get-package-type@npm:0.1.0" + checksum: 10/bba0811116d11e56d702682ddef7c73ba3481f114590e705fc549f4d868972263896af313c57a25c076e3c0d567e11d919a64ba1b30c879be985fc9d44f96148 + languageName: node + linkType: hard + +"get-stream@npm:^6.0.0": + version: 6.0.1 + resolution: "get-stream@npm:6.0.1" + checksum: 10/781266d29725f35c59f1d214aedc92b0ae855800a980800e2923b3fbc4e56b3cb6e462c42e09a1cf1a00c64e056a78fa407cbe06c7c92b7e5cd49b4b85c2a497 + languageName: node + linkType: hard + "glob@npm:^10.2.2": version: 10.4.5 resolution: "glob@npm:10.4.5" @@ -1224,13 +2495,57 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.2.6": +"glob@npm:^7.1.3, glob@npm:^7.1.4": + version: 7.2.3 + resolution: "glob@npm:7.2.3" + dependencies: + fs.realpath: "npm:^1.0.0" + inflight: "npm:^1.0.4" + inherits: "npm:2" + minimatch: "npm:^3.1.1" + once: "npm:^1.3.0" + path-is-absolute: "npm:^1.0.0" + checksum: 10/59452a9202c81d4508a43b8af7082ca5c76452b9fcc4a9ab17655822e6ce9b21d4f8fbadabe4fe3faef448294cec249af305e2cd824b7e9aaf689240e5e96a7b + languageName: node + linkType: hard + +"globals@npm:^11.1.0": + version: 11.12.0 + resolution: "globals@npm:11.12.0" + checksum: 10/9f054fa38ff8de8fa356502eb9d2dae0c928217b8b5c8de1f09f5c9b6c8a96d8b9bd3afc49acbcd384a98a81fea713c859e1b09e214c60509517bb8fc2bc13c2 + languageName: node + linkType: hard + +"graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 languageName: node linkType: hard +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 10/261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad + languageName: node + linkType: hard + +"hasown@npm:^2.0.2": + version: 2.0.2 + resolution: "hasown@npm:2.0.2" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10/7898a9c1788b2862cf0f9c345a6bec77ba4a0c0983c7f19d610c382343d4f98fa260686b225dfb1f88393a66679d2ec58ee310c1d6868c081eda7918f32cc70a + languageName: node + linkType: hard + +"html-escaper@npm:^2.0.0": + version: 2.0.2 + resolution: "html-escaper@npm:2.0.2" + checksum: 10/034d74029dcca544a34fb6135e98d427acd73019796ffc17383eaa3ec2fe1c0471dcbbc8f8ed39e46e86d43ccd753a160631615e4048285e313569609b66d5b7 + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.1.1": version: 4.2.0 resolution: "http-cache-semantics@npm:4.2.0" @@ -1258,6 +2573,13 @@ __metadata: languageName: node linkType: hard +"human-signals@npm:^2.1.0": + version: 2.1.0 + resolution: "human-signals@npm:2.1.0" + checksum: 10/df59be9e0af479036798a881d1f136c4a29e0b518d4abb863afbd11bf30efa3eeb1d0425fc65942dcc05ab3bf40205ea436b0ff389f2cd20b75b8643d539bf86 + languageName: node + linkType: hard + "iconv-lite@npm:^0.6.2": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" @@ -1267,6 +2589,18 @@ __metadata: languageName: node linkType: hard +"import-local@npm:^3.0.2": + version: 3.2.0 + resolution: "import-local@npm:3.2.0" + dependencies: + pkg-dir: "npm:^4.2.0" + resolve-cwd: "npm:^3.0.0" + bin: + import-local-fixture: fixtures/cli.js + checksum: 10/0b0b0b412b2521739fbb85eeed834a3c34de9bc67e670b3d0b86248fc460d990a7b116ad056c084b87a693ef73d1f17268d6a5be626bb43c998a8b1c8a230004 + languageName: node + linkType: hard + "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -1274,6 +2608,23 @@ __metadata: languageName: node linkType: hard +"inflight@npm:^1.0.4": + version: 1.0.6 + resolution: "inflight@npm:1.0.6" + dependencies: + once: "npm:^1.3.0" + wrappy: "npm:1" + checksum: 10/d2ebd65441a38c8336c223d1b80b921b9fa737e37ea466fd7e253cb000c64ae1f17fa59e68130ef5bda92cfd8d36b83d37dab0eb0a4558bcfec8e8cdfd2dcb67 + languageName: node + linkType: hard + +"inherits@npm:2": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 10/cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521 + languageName: node + linkType: hard + "ip-address@npm:^9.0.5": version: 9.0.5 resolution: "ip-address@npm:9.0.5" @@ -1284,6 +2635,22 @@ __metadata: languageName: node linkType: hard +"is-arrayish@npm:^0.2.1": + version: 0.2.1 + resolution: "is-arrayish@npm:0.2.1" + checksum: 10/73ced84fa35e59e2c57da2d01e12cd01479f381d7f122ce41dcbb713f09dbfc651315832cd2bf8accba7681a69e4d6f1e03941d94dd10040d415086360e7005e + languageName: node + linkType: hard + +"is-core-module@npm:^2.16.0": + version: 2.16.1 + resolution: "is-core-module@npm:2.16.1" + dependencies: + hasown: "npm:^2.0.2" + checksum: 10/452b2c2fb7f889cbbf7e54609ef92cf6c24637c568acc7e63d166812a0fb365ae8a504c333a29add8bdb1686704068caa7f4e4b639b650dde4f00a038b8941fb + languageName: node + linkType: hard + "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -1291,6 +2658,13 @@ __metadata: languageName: node linkType: hard +"is-generator-fn@npm:^2.0.0": + version: 2.1.0 + resolution: "is-generator-fn@npm:2.1.0" + checksum: 10/a6ad5492cf9d1746f73b6744e0c43c0020510b59d56ddcb78a91cbc173f09b5e6beff53d75c9c5a29feb618bfef2bf458e025ecf3a57ad2268e2fb2569f56215 + languageName: node + linkType: hard + "is-interactive@npm:^2.0.0": version: 2.0.0 resolution: "is-interactive@npm:2.0.0" @@ -1298,6 +2672,20 @@ __metadata: languageName: node linkType: hard +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 10/6a6c3383f68afa1e05b286af866017c78f1226d43ac8cb064e115ff9ed85eb33f5c4f7216c96a71e4dfea289ef52c5da3aef5bbfade8ffe47a0465d70c0c8e86 + languageName: node + linkType: hard + +"is-stream@npm:^2.0.0": + version: 2.0.1 + resolution: "is-stream@npm:2.0.1" + checksum: 10/b8e05ccdf96ac330ea83c12450304d4a591f9958c11fd17bed240af8d5ffe08aedafa4c0f4cfccd4d28dc9d4d129daca1023633d5c11601a6cbc77521f6fae66 + languageName: node + linkType: hard + "is-unicode-supported@npm:^1.3.0": version: 1.3.0 resolution: "is-unicode-supported@npm:1.3.0" @@ -1326,6 +2714,71 @@ __metadata: languageName: node linkType: hard +"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": + version: 3.2.2 + resolution: "istanbul-lib-coverage@npm:3.2.2" + checksum: 10/40bbdd1e937dfd8c830fa286d0f665e81b7a78bdabcd4565f6d5667c99828bda3db7fb7ac6b96a3e2e8a2461ddbc5452d9f8bc7d00cb00075fa6a3e99f5b6a81 + languageName: node + linkType: hard + +"istanbul-lib-instrument@npm:^5.0.4": + version: 5.2.1 + resolution: "istanbul-lib-instrument@npm:5.2.1" + dependencies: + "@babel/core": "npm:^7.12.3" + "@babel/parser": "npm:^7.14.7" + "@istanbuljs/schema": "npm:^0.1.2" + istanbul-lib-coverage: "npm:^3.2.0" + semver: "npm:^6.3.0" + checksum: 10/bbc4496c2f304d799f8ec22202ab38c010ac265c441947f075c0f7d46bd440b45c00e46017cf9053453d42182d768b1d6ed0e70a142c95ab00df9843aa5ab80e + languageName: node + linkType: hard + +"istanbul-lib-instrument@npm:^6.0.0": + version: 6.0.3 + resolution: "istanbul-lib-instrument@npm:6.0.3" + dependencies: + "@babel/core": "npm:^7.23.9" + "@babel/parser": "npm:^7.23.9" + "@istanbuljs/schema": "npm:^0.1.3" + istanbul-lib-coverage: "npm:^3.2.0" + semver: "npm:^7.5.4" + checksum: 10/aa5271c0008dfa71b6ecc9ba1e801bf77b49dc05524e8c30d58aaf5b9505e0cd12f25f93165464d4266a518c5c75284ecb598fbd89fec081ae77d2c9d3327695 + languageName: node + linkType: hard + +"istanbul-lib-report@npm:^3.0.0": + version: 3.0.1 + resolution: "istanbul-lib-report@npm:3.0.1" + dependencies: + istanbul-lib-coverage: "npm:^3.0.0" + make-dir: "npm:^4.0.0" + supports-color: "npm:^7.1.0" + checksum: 10/86a83421ca1cf2109a9f6d193c06c31ef04a45e72a74579b11060b1e7bb9b6337a4e6f04abfb8857e2d569c271273c65e855ee429376a0d7c91ad91db42accd1 + languageName: node + linkType: hard + +"istanbul-lib-source-maps@npm:^4.0.0": + version: 4.0.1 + resolution: "istanbul-lib-source-maps@npm:4.0.1" + dependencies: + debug: "npm:^4.1.1" + istanbul-lib-coverage: "npm:^3.0.0" + source-map: "npm:^0.6.1" + checksum: 10/5526983462799aced011d776af166e350191b816821ea7bcf71cab3e5272657b062c47dc30697a22a43656e3ced78893a42de677f9ccf276a28c913190953b82 + languageName: node + linkType: hard + +"istanbul-reports@npm:^3.1.3": + version: 3.1.7 + resolution: "istanbul-reports@npm:3.1.7" + dependencies: + html-escaper: "npm:^2.0.0" + istanbul-lib-report: "npm:^3.0.0" + checksum: 10/f1faaa4684efaf57d64087776018d7426312a59aa6eeb4e0e3a777347d23cd286ad18f427e98f0e3dee666103d7404c9d7abc5f240406a912fa16bd6695437fa + languageName: node + linkType: hard + "jackspeak@npm:^3.1.2": version: 3.4.3 resolution: "jackspeak@npm:3.4.3" @@ -1339,6 +2792,464 @@ __metadata: languageName: node linkType: hard +"jest-changed-files@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-changed-files@npm:29.7.0" + dependencies: + execa: "npm:^5.0.0" + jest-util: "npm:^29.7.0" + p-limit: "npm:^3.1.0" + checksum: 10/3d93742e56b1a73a145d55b66e96711fbf87ef89b96c2fab7cfdfba8ec06612591a982111ca2b712bb853dbc16831ec8b43585a2a96b83862d6767de59cbf83d + languageName: node + linkType: hard + +"jest-circus@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-circus@npm:29.7.0" + dependencies: + "@jest/environment": "npm:^29.7.0" + "@jest/expect": "npm:^29.7.0" + "@jest/test-result": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + "@types/node": "npm:*" + chalk: "npm:^4.0.0" + co: "npm:^4.6.0" + dedent: "npm:^1.0.0" + is-generator-fn: "npm:^2.0.0" + jest-each: "npm:^29.7.0" + jest-matcher-utils: "npm:^29.7.0" + jest-message-util: "npm:^29.7.0" + jest-runtime: "npm:^29.7.0" + jest-snapshot: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + p-limit: "npm:^3.1.0" + pretty-format: "npm:^29.7.0" + pure-rand: "npm:^6.0.0" + slash: "npm:^3.0.0" + stack-utils: "npm:^2.0.3" + checksum: 10/716a8e3f40572fd0213bcfc1da90274bf30d856e5133af58089a6ce45089b63f4d679bd44e6be9d320e8390483ebc3ae9921981993986d21639d9019b523123d + languageName: node + linkType: hard + +"jest-cli@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-cli@npm:29.7.0" + dependencies: + "@jest/core": "npm:^29.7.0" + "@jest/test-result": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + chalk: "npm:^4.0.0" + create-jest: "npm:^29.7.0" + exit: "npm:^0.1.2" + import-local: "npm:^3.0.2" + jest-config: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + jest-validate: "npm:^29.7.0" + yargs: "npm:^17.3.1" + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + bin: + jest: bin/jest.js + checksum: 10/6cc62b34d002c034203065a31e5e9a19e7c76d9e8ef447a6f70f759c0714cb212c6245f75e270ba458620f9c7b26063cd8cf6cd1f7e3afd659a7cc08add17307 + languageName: node + linkType: hard + +"jest-config@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-config@npm:29.7.0" + dependencies: + "@babel/core": "npm:^7.11.6" + "@jest/test-sequencer": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + babel-jest: "npm:^29.7.0" + chalk: "npm:^4.0.0" + ci-info: "npm:^3.2.0" + deepmerge: "npm:^4.2.2" + glob: "npm:^7.1.3" + graceful-fs: "npm:^4.2.9" + jest-circus: "npm:^29.7.0" + jest-environment-node: "npm:^29.7.0" + jest-get-type: "npm:^29.6.3" + jest-regex-util: "npm:^29.6.3" + jest-resolve: "npm:^29.7.0" + jest-runner: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + jest-validate: "npm:^29.7.0" + micromatch: "npm:^4.0.4" + parse-json: "npm:^5.2.0" + pretty-format: "npm:^29.7.0" + slash: "npm:^3.0.0" + strip-json-comments: "npm:^3.1.1" + peerDependencies: + "@types/node": "*" + ts-node: ">=9.0.0" + peerDependenciesMeta: + "@types/node": + optional: true + ts-node: + optional: true + checksum: 10/6bdf570e9592e7d7dd5124fc0e21f5fe92bd15033513632431b211797e3ab57eaa312f83cc6481b3094b72324e369e876f163579d60016677c117ec4853cf02b + languageName: node + linkType: hard + +"jest-diff@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-diff@npm:29.7.0" + dependencies: + chalk: "npm:^4.0.0" + diff-sequences: "npm:^29.6.3" + jest-get-type: "npm:^29.6.3" + pretty-format: "npm:^29.7.0" + checksum: 10/6f3a7eb9cd9de5ea9e5aa94aed535631fa6f80221832952839b3cb59dd419b91c20b73887deb0b62230d06d02d6b6cf34ebb810b88d904bb4fe1e2e4f0905c98 + languageName: node + linkType: hard + +"jest-docblock@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-docblock@npm:29.7.0" + dependencies: + detect-newline: "npm:^3.0.0" + checksum: 10/8d48818055bc96c9e4ec2e217a5a375623c0d0bfae8d22c26e011074940c202aa2534a3362294c81d981046885c05d304376afba9f2874143025981148f3e96d + languageName: node + linkType: hard + +"jest-each@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-each@npm:29.7.0" + dependencies: + "@jest/types": "npm:^29.6.3" + chalk: "npm:^4.0.0" + jest-get-type: "npm:^29.6.3" + jest-util: "npm:^29.7.0" + pretty-format: "npm:^29.7.0" + checksum: 10/bd1a077654bdaa013b590deb5f7e7ade68f2e3289180a8c8f53bc8a49f3b40740c0ec2d3a3c1aee906f682775be2bebbac37491d80b634d15276b0aa0f2e3fda + languageName: node + linkType: hard + +"jest-environment-node@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-environment-node@npm:29.7.0" + dependencies: + "@jest/environment": "npm:^29.7.0" + "@jest/fake-timers": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + "@types/node": "npm:*" + jest-mock: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + checksum: 10/9cf7045adf2307cc93aed2f8488942e39388bff47ec1df149a997c6f714bfc66b2056768973770d3f8b1bf47396c19aa564877eb10ec978b952c6018ed1bd637 + languageName: node + linkType: hard + +"jest-get-type@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-get-type@npm:29.6.3" + checksum: 10/88ac9102d4679d768accae29f1e75f592b760b44277df288ad76ce5bf038c3f5ce3719dea8aa0f035dac30e9eb034b848ce716b9183ad7cc222d029f03e92205 + languageName: node + linkType: hard + +"jest-haste-map@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-haste-map@npm:29.7.0" + dependencies: + "@jest/types": "npm:^29.6.3" + "@types/graceful-fs": "npm:^4.1.3" + "@types/node": "npm:*" + anymatch: "npm:^3.0.3" + fb-watchman: "npm:^2.0.0" + fsevents: "npm:^2.3.2" + graceful-fs: "npm:^4.2.9" + jest-regex-util: "npm:^29.6.3" + jest-util: "npm:^29.7.0" + jest-worker: "npm:^29.7.0" + micromatch: "npm:^4.0.4" + walker: "npm:^1.0.8" + dependenciesMeta: + fsevents: + optional: true + checksum: 10/8531b42003581cb18a69a2774e68c456fb5a5c3280b1b9b77475af9e346b6a457250f9d756bfeeae2fe6cbc9ef28434c205edab9390ee970a919baddfa08bb85 + languageName: node + linkType: hard + +"jest-leak-detector@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-leak-detector@npm:29.7.0" + dependencies: + jest-get-type: "npm:^29.6.3" + pretty-format: "npm:^29.7.0" + checksum: 10/e3950e3ddd71e1d0c22924c51a300a1c2db6cf69ec1e51f95ccf424bcc070f78664813bef7aed4b16b96dfbdeea53fe358f8aeaaea84346ae15c3735758f1605 + languageName: node + linkType: hard + +"jest-matcher-utils@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-matcher-utils@npm:29.7.0" + dependencies: + chalk: "npm:^4.0.0" + jest-diff: "npm:^29.7.0" + jest-get-type: "npm:^29.6.3" + pretty-format: "npm:^29.7.0" + checksum: 10/981904a494299cf1e3baed352f8a3bd8b50a8c13a662c509b6a53c31461f94ea3bfeffa9d5efcfeb248e384e318c87de7e3baa6af0f79674e987482aa189af40 + languageName: node + linkType: hard + +"jest-message-util@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-message-util@npm:29.7.0" + dependencies: + "@babel/code-frame": "npm:^7.12.13" + "@jest/types": "npm:^29.6.3" + "@types/stack-utils": "npm:^2.0.0" + chalk: "npm:^4.0.0" + graceful-fs: "npm:^4.2.9" + micromatch: "npm:^4.0.4" + pretty-format: "npm:^29.7.0" + slash: "npm:^3.0.0" + stack-utils: "npm:^2.0.3" + checksum: 10/31d53c6ed22095d86bab9d14c0fa70c4a92c749ea6ceece82cf30c22c9c0e26407acdfbdb0231435dc85a98d6d65ca0d9cbcd25cd1abb377fe945e843fb770b9 + languageName: node + linkType: hard + +"jest-mock@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-mock@npm:29.7.0" + dependencies: + "@jest/types": "npm:^29.6.3" + "@types/node": "npm:*" + jest-util: "npm:^29.7.0" + checksum: 10/ae51d1b4f898724be5e0e52b2268a68fcd876d9b20633c864a6dd6b1994cbc48d62402b0f40f3a1b669b30ebd648821f086c26c08ffde192ced951ff4670d51c + languageName: node + linkType: hard + +"jest-pnp-resolver@npm:^1.2.2": + version: 1.2.3 + resolution: "jest-pnp-resolver@npm:1.2.3" + peerDependencies: + jest-resolve: "*" + peerDependenciesMeta: + jest-resolve: + optional: true + checksum: 10/db1a8ab2cb97ca19c01b1cfa9a9c8c69a143fde833c14df1fab0766f411b1148ff0df878adea09007ac6a2085ec116ba9a996a6ad104b1e58c20adbf88eed9b2 + languageName: node + linkType: hard + +"jest-regex-util@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-regex-util@npm:29.6.3" + checksum: 10/0518beeb9bf1228261695e54f0feaad3606df26a19764bc19541e0fc6e2a3737191904607fb72f3f2ce85d9c16b28df79b7b1ec9443aa08c3ef0e9efda6f8f2a + languageName: node + linkType: hard + +"jest-resolve-dependencies@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-resolve-dependencies@npm:29.7.0" + dependencies: + jest-regex-util: "npm:^29.6.3" + jest-snapshot: "npm:^29.7.0" + checksum: 10/1e206f94a660d81e977bcfb1baae6450cb4a81c92e06fad376cc5ea16b8e8c6ea78c383f39e95591a9eb7f925b6a1021086c38941aa7c1b8a6a813c2f6e93675 + languageName: node + linkType: hard + +"jest-resolve@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-resolve@npm:29.7.0" + dependencies: + chalk: "npm:^4.0.0" + graceful-fs: "npm:^4.2.9" + jest-haste-map: "npm:^29.7.0" + jest-pnp-resolver: "npm:^1.2.2" + jest-util: "npm:^29.7.0" + jest-validate: "npm:^29.7.0" + resolve: "npm:^1.20.0" + resolve.exports: "npm:^2.0.0" + slash: "npm:^3.0.0" + checksum: 10/faa466fd9bc69ea6c37a545a7c6e808e073c66f46ab7d3d8a6ef084f8708f201b85d5fe1799789578b8b47fa1de47b9ee47b414d1863bc117a49e032ba77b7c7 + languageName: node + linkType: hard + +"jest-runner@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-runner@npm:29.7.0" + dependencies: + "@jest/console": "npm:^29.7.0" + "@jest/environment": "npm:^29.7.0" + "@jest/test-result": "npm:^29.7.0" + "@jest/transform": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + "@types/node": "npm:*" + chalk: "npm:^4.0.0" + emittery: "npm:^0.13.1" + graceful-fs: "npm:^4.2.9" + jest-docblock: "npm:^29.7.0" + jest-environment-node: "npm:^29.7.0" + jest-haste-map: "npm:^29.7.0" + jest-leak-detector: "npm:^29.7.0" + jest-message-util: "npm:^29.7.0" + jest-resolve: "npm:^29.7.0" + jest-runtime: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + jest-watcher: "npm:^29.7.0" + jest-worker: "npm:^29.7.0" + p-limit: "npm:^3.1.0" + source-map-support: "npm:0.5.13" + checksum: 10/9d8748a494bd90f5c82acea99be9e99f21358263ce6feae44d3f1b0cd90991b5df5d18d607e73c07be95861ee86d1cbab2a3fc6ca4b21805f07ac29d47c1da1e + languageName: node + linkType: hard + +"jest-runtime@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-runtime@npm:29.7.0" + dependencies: + "@jest/environment": "npm:^29.7.0" + "@jest/fake-timers": "npm:^29.7.0" + "@jest/globals": "npm:^29.7.0" + "@jest/source-map": "npm:^29.6.3" + "@jest/test-result": "npm:^29.7.0" + "@jest/transform": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + "@types/node": "npm:*" + chalk: "npm:^4.0.0" + cjs-module-lexer: "npm:^1.0.0" + collect-v8-coverage: "npm:^1.0.0" + glob: "npm:^7.1.3" + graceful-fs: "npm:^4.2.9" + jest-haste-map: "npm:^29.7.0" + jest-message-util: "npm:^29.7.0" + jest-mock: "npm:^29.7.0" + jest-regex-util: "npm:^29.6.3" + jest-resolve: "npm:^29.7.0" + jest-snapshot: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + slash: "npm:^3.0.0" + strip-bom: "npm:^4.0.0" + checksum: 10/59eb58eb7e150e0834a2d0c0d94f2a0b963ae7182cfa6c63f2b49b9c6ef794e5193ef1634e01db41420c36a94cefc512cdd67a055cd3e6fa2f41eaf0f82f5a20 + languageName: node + linkType: hard + +"jest-snapshot@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-snapshot@npm:29.7.0" + dependencies: + "@babel/core": "npm:^7.11.6" + "@babel/generator": "npm:^7.7.2" + "@babel/plugin-syntax-jsx": "npm:^7.7.2" + "@babel/plugin-syntax-typescript": "npm:^7.7.2" + "@babel/types": "npm:^7.3.3" + "@jest/expect-utils": "npm:^29.7.0" + "@jest/transform": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + babel-preset-current-node-syntax: "npm:^1.0.0" + chalk: "npm:^4.0.0" + expect: "npm:^29.7.0" + graceful-fs: "npm:^4.2.9" + jest-diff: "npm:^29.7.0" + jest-get-type: "npm:^29.6.3" + jest-matcher-utils: "npm:^29.7.0" + jest-message-util: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + natural-compare: "npm:^1.4.0" + pretty-format: "npm:^29.7.0" + semver: "npm:^7.5.3" + checksum: 10/cb19a3948256de5f922d52f251821f99657339969bf86843bd26cf3332eae94883e8260e3d2fba46129a27c3971c1aa522490e460e16c7fad516e82d10bbf9f8 + languageName: node + linkType: hard + +"jest-util@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-util@npm:29.7.0" + dependencies: + "@jest/types": "npm:^29.6.3" + "@types/node": "npm:*" + chalk: "npm:^4.0.0" + ci-info: "npm:^3.2.0" + graceful-fs: "npm:^4.2.9" + picomatch: "npm:^2.2.3" + checksum: 10/30d58af6967e7d42bd903ccc098f3b4d3859ed46238fbc88d4add6a3f10bea00c226b93660285f058bc7a65f6f9529cf4eb80f8d4707f79f9e3a23686b4ab8f3 + languageName: node + linkType: hard + +"jest-validate@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-validate@npm:29.7.0" + dependencies: + "@jest/types": "npm:^29.6.3" + camelcase: "npm:^6.2.0" + chalk: "npm:^4.0.0" + jest-get-type: "npm:^29.6.3" + leven: "npm:^3.1.0" + pretty-format: "npm:^29.7.0" + checksum: 10/8ee1163666d8eaa16d90a989edba2b4a3c8ab0ffaa95ad91b08ca42b015bfb70e164b247a5b17f9de32d096987cada63ed8491ab82761bfb9a28bc34b27ae161 + languageName: node + linkType: hard + +"jest-watcher@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-watcher@npm:29.7.0" + dependencies: + "@jest/test-result": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + "@types/node": "npm:*" + ansi-escapes: "npm:^4.2.1" + chalk: "npm:^4.0.0" + emittery: "npm:^0.13.1" + jest-util: "npm:^29.7.0" + string-length: "npm:^4.0.1" + checksum: 10/4f616e0345676631a7034b1d94971aaa719f0cd4a6041be2aa299be437ea047afd4fe05c48873b7963f5687a2f6c7cbf51244be8b14e313b97bfe32b1e127e55 + languageName: node + linkType: hard + +"jest-worker@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-worker@npm:29.7.0" + dependencies: + "@types/node": "npm:*" + jest-util: "npm:^29.7.0" + merge-stream: "npm:^2.0.0" + supports-color: "npm:^8.0.0" + checksum: 10/364cbaef00d8a2729fc760227ad34b5e60829e0869bd84976bdfbd8c0d0f9c2f22677b3e6dd8afa76ed174765351cd12bae3d4530c62eefb3791055127ca9745 + languageName: node + linkType: hard + +"jest@npm:^29.7.0": + version: 29.7.0 + resolution: "jest@npm:29.7.0" + dependencies: + "@jest/core": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + import-local: "npm:^3.0.2" + jest-cli: "npm:^29.7.0" + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + bin: + jest: bin/jest.js + checksum: 10/97023d78446098c586faaa467fbf2c6b07ff06e2c85a19e3926adb5b0effe9ac60c4913ae03e2719f9c01ae8ffd8d92f6b262cedb9555ceeb5d19263d8c6362a + languageName: node + linkType: hard + +"js-tokens@npm:^4.0.0": + version: 4.0.0 + resolution: "js-tokens@npm:4.0.0" + checksum: 10/af37d0d913fb56aec6dc0074c163cc71cd23c0b8aad5c2350747b6721d37ba118af35abdd8b33c47ec2800de07dedb16a527ca9c530ee004093e04958bd0cbf2 + languageName: node + linkType: hard + +"js-yaml@npm:^3.13.1": + version: 3.14.1 + resolution: "js-yaml@npm:3.14.1" + dependencies: + argparse: "npm:^1.0.7" + esprima: "npm:^4.0.0" + bin: + js-yaml: bin/js-yaml.js + checksum: 10/9e22d80b4d0105b9899135365f746d47466ed53ef4223c529b3c0f7a39907743fdbd3c4379f94f1106f02755b5e90b2faaf84801a891135544e1ea475d1a1379 + languageName: node + linkType: hard + "jsbn@npm:1.1.0": version: 1.1.0 resolution: "jsbn@npm:1.1.0" @@ -1346,6 +3257,61 @@ __metadata: languageName: node linkType: hard +"jsesc@npm:^3.0.2": + version: 3.1.0 + resolution: "jsesc@npm:3.1.0" + bin: + jsesc: bin/jsesc + checksum: 10/20bd37a142eca5d1794f354db8f1c9aeb54d85e1f5c247b371de05d23a9751ecd7bd3a9c4fc5298ea6fa09a100dafb4190fa5c98c6610b75952c3487f3ce7967 + languageName: node + linkType: hard + +"json-parse-even-better-errors@npm:^2.3.0": + version: 2.3.1 + resolution: "json-parse-even-better-errors@npm:2.3.1" + checksum: 10/5f3a99009ed5f2a5a67d06e2f298cc97bc86d462034173308156f15b43a6e850be8511dc204b9b94566305da2947f7d90289657237d210351a39059ff9d666cf + languageName: node + linkType: hard + +"json5@npm:^2.2.3": + version: 2.2.3 + resolution: "json5@npm:2.2.3" + bin: + json5: lib/cli.js + checksum: 10/1db67b853ff0de3534085d630691d3247de53a2ed1390ba0ddff681ea43e9b3e30ecbdb65c5e9aab49435e44059c23dbd6fee8ee619419ba37465bb0dd7135da + languageName: node + linkType: hard + +"kleur@npm:^3.0.3": + version: 3.0.3 + resolution: "kleur@npm:3.0.3" + checksum: 10/0c0ecaf00a5c6173d25059c7db2113850b5457016dfa1d0e3ef26da4704fbb186b4938d7611246d86f0ddf1bccf26828daa5877b1f232a65e7373d0122a83e7f + languageName: node + linkType: hard + +"leven@npm:^3.1.0": + version: 3.1.0 + resolution: "leven@npm:3.1.0" + checksum: 10/638401d534585261b6003db9d99afd244dfe82d75ddb6db5c0df412842d5ab30b2ef18de471aaec70fe69a46f17b4ae3c7f01d8a4e6580ef7adb9f4273ad1e55 + languageName: node + linkType: hard + +"lines-and-columns@npm:^1.1.6": + version: 1.2.4 + resolution: "lines-and-columns@npm:1.2.4" + checksum: 10/0c37f9f7fa212b38912b7145e1cd16a5f3cd34d782441c3e6ca653485d326f58b3caccda66efce1c5812bde4961bbde3374fae4b0d11bf1226152337f3894aa5 + languageName: node + linkType: hard + +"locate-path@npm:^5.0.0": + version: 5.0.0 + resolution: "locate-path@npm:5.0.0" + dependencies: + p-locate: "npm:^4.1.0" + checksum: 10/83e51725e67517287d73e1ded92b28602e3ae5580b301fe54bfb76c0c723e3f285b19252e375712316774cf52006cb236aed5704692c32db0d5d089b69696e30 + languageName: node + linkType: hard + "log-symbols@npm:^6.0.0": version: 6.0.0 resolution: "log-symbols@npm:6.0.0" @@ -1380,6 +3346,15 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^5.1.1": + version: 5.1.1 + resolution: "lru-cache@npm:5.1.1" + dependencies: + yallist: "npm:^3.0.2" + checksum: 10/951d2673dcc64a7fb888bf3d13bc2fdf923faca97d89cdb405ba3dfff77e2b26e5798d405e78fcd7094c9e7b8b4dab2ddc5a4f8a11928af24a207b7c738ca3f8 + languageName: node + linkType: hard + "magic-string@npm:^0.30.17": version: 0.30.17 resolution: "magic-string@npm:0.30.17" @@ -1389,6 +3364,15 @@ __metadata: languageName: node linkType: hard +"make-dir@npm:^4.0.0": + version: 4.0.0 + resolution: "make-dir@npm:4.0.0" + dependencies: + semver: "npm:^7.5.3" + checksum: 10/bf0731a2dd3aab4db6f3de1585cea0b746bb73eb5a02e3d8d72757e376e64e6ada190b1eddcde5b2f24a81b688a9897efd5018737d05e02e2a671dda9cff8a8a + languageName: node + linkType: hard + "make-error@npm:^1.1.1": version: 1.3.6 resolution: "make-error@npm:1.3.6" @@ -1415,6 +3399,39 @@ __metadata: languageName: node linkType: hard +"makeerror@npm:1.0.12": + version: 1.0.12 + resolution: "makeerror@npm:1.0.12" + dependencies: + tmpl: "npm:1.0.5" + checksum: 10/4c66ddfc654537333da952c084f507fa4c30c707b1635344eb35be894d797ba44c901a9cebe914aa29a7f61357543ba09b09dddbd7f65b4aee756b450f169f40 + languageName: node + linkType: hard + +"merge-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "merge-stream@npm:2.0.0" + checksum: 10/6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 + languageName: node + linkType: hard + +"micromatch@npm:^4.0.4": + version: 4.0.8 + resolution: "micromatch@npm:4.0.8" + dependencies: + braces: "npm:^3.0.3" + picomatch: "npm:^2.3.1" + checksum: 10/6bf2a01672e7965eb9941d1f02044fad2bd12486b5553dc1116ff24c09a8723157601dc992e74c911d896175918448762df3b3fd0a6b61037dd1a9766ddfbf58 + languageName: node + linkType: hard + +"mimic-fn@npm:^2.1.0": + version: 2.1.0 + resolution: "mimic-fn@npm:2.1.0" + checksum: 10/d2421a3444848ce7f84bd49115ddacff29c15745db73f54041edc906c14b131a38d05298dae3081667627a59b2eb1ca4b436ff2e1b80f69679522410418b478a + languageName: node + linkType: hard + "mimic-function@npm:^5.0.0": version: 5.0.1 resolution: "mimic-function@npm:5.0.1" @@ -1422,6 +3439,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: "npm:^1.1.7" + checksum: 10/e0b25b04cd4ec6732830344e5739b13f8690f8a012d73445a4a19fbc623f5dd481ef7a5827fde25954cd6026fede7574cc54dc4643c99d6c6b653d6203f94634 + languageName: node + linkType: hard + "minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -1532,6 +3558,13 @@ __metadata: languageName: node linkType: hard +"natural-compare@npm:^1.4.0": + version: 1.4.0 + resolution: "natural-compare@npm:1.4.0" + checksum: 10/23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d + languageName: node + linkType: hard + "negotiator@npm:^1.0.0": version: 1.0.0 resolution: "negotiator@npm:1.0.0" @@ -1559,6 +3592,20 @@ __metadata: languageName: node linkType: hard +"node-int64@npm:^0.4.0": + version: 0.4.0 + resolution: "node-int64@npm:0.4.0" + checksum: 10/b7afc2b65e56f7035b1a2eec57ae0fbdee7d742b1cdcd0f4387562b6527a011ab1cbe9f64cc8b3cca61e3297c9637c8bf61cec2e6b8d3a711d4b5267dfafbe02 + languageName: node + linkType: hard + +"node-releases@npm:^2.0.19": + version: 2.0.19 + resolution: "node-releases@npm:2.0.19" + checksum: 10/c2b33b4f0c40445aee56141f13ca692fa6805db88510e5bbb3baadb2da13e1293b738e638e15e4a8eb668bb9e97debb08e7a35409b477b5cc18f171d35a83045 + languageName: node + linkType: hard + "nopt@npm:^8.0.0": version: 8.1.0 resolution: "nopt@npm:8.1.0" @@ -1570,6 +3617,22 @@ __metadata: languageName: node linkType: hard +"normalize-path@npm:^3.0.0": + version: 3.0.0 + resolution: "normalize-path@npm:3.0.0" + checksum: 10/88eeb4da891e10b1318c4b2476b6e2ecbeb5ff97d946815ffea7794c31a89017c70d7f34b3c2ebf23ef4e9fc9fb99f7dffe36da22011b5b5c6ffa34f4873ec20 + languageName: node + linkType: hard + +"npm-run-path@npm:^4.0.1": + version: 4.0.1 + resolution: "npm-run-path@npm:4.0.1" + dependencies: + path-key: "npm:^3.0.0" + checksum: 10/5374c0cea4b0bbfdfae62da7bbdf1e1558d338335f4cacf2515c282ff358ff27b2ecb91ffa5330a8b14390ac66a1e146e10700440c1ab868208430f56b5f4d23 + languageName: node + linkType: hard + "object-inspect@npm:^1.12.3": version: 1.13.4 resolution: "object-inspect@npm:1.13.4" @@ -1577,6 +3640,24 @@ __metadata: languageName: node linkType: hard +"once@npm:^1.3.0": + version: 1.4.0 + resolution: "once@npm:1.4.0" + dependencies: + wrappy: "npm:1" + checksum: 10/cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 + languageName: node + linkType: hard + +"onetime@npm:^5.1.2": + version: 5.1.2 + resolution: "onetime@npm:5.1.2" + dependencies: + mimic-fn: "npm:^2.1.0" + checksum: 10/e9fd0695a01cf226652f0385bf16b7a24153dbbb2039f764c8ba6d2306a8506b0e4ce570de6ad99c7a6eb49520743afdb66edd95ee979c1a342554ed49a9aadd + languageName: node + linkType: hard + "onetime@npm:^7.0.0": version: 7.0.0 resolution: "onetime@npm:7.0.0" @@ -1603,6 +3684,33 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^2.2.0": + version: 2.3.0 + resolution: "p-limit@npm:2.3.0" + dependencies: + p-try: "npm:^2.0.0" + checksum: 10/84ff17f1a38126c3314e91ecfe56aecbf36430940e2873dadaa773ffe072dc23b7af8e46d4b6485d302a11673fe94c6b67ca2cfbb60c989848b02100d0594ac1 + languageName: node + linkType: hard + +"p-limit@npm:^3.1.0": + version: 3.1.0 + resolution: "p-limit@npm:3.1.0" + dependencies: + yocto-queue: "npm:^0.1.0" + checksum: 10/7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360 + languageName: node + linkType: hard + +"p-locate@npm:^4.1.0": + version: 4.1.0 + resolution: "p-locate@npm:4.1.0" + dependencies: + p-limit: "npm:^2.2.0" + checksum: 10/513bd14a455f5da4ebfcb819ef706c54adb09097703de6aeaa5d26fe5ea16df92b48d1ac45e01e3944ce1e6aa2a66f7f8894742b8c9d6e276e16cd2049a2b870 + languageName: node + linkType: hard + "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" @@ -1610,6 +3718,13 @@ __metadata: languageName: node linkType: hard +"p-try@npm:^2.0.0": + version: 2.2.0 + resolution: "p-try@npm:2.2.0" + checksum: 10/f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae + languageName: node + linkType: hard + "package-json-from-dist@npm:^1.0.0": version: 1.0.1 resolution: "package-json-from-dist@npm:1.0.1" @@ -1617,13 +3732,46 @@ __metadata: languageName: node linkType: hard -"path-key@npm:^3.1.0": +"parse-json@npm:^5.2.0": + version: 5.2.0 + resolution: "parse-json@npm:5.2.0" + dependencies: + "@babel/code-frame": "npm:^7.0.0" + error-ex: "npm:^1.3.1" + json-parse-even-better-errors: "npm:^2.3.0" + lines-and-columns: "npm:^1.1.6" + checksum: 10/62085b17d64da57f40f6afc2ac1f4d95def18c4323577e1eced571db75d9ab59b297d1d10582920f84b15985cbfc6b6d450ccbf317644cfa176f3ed982ad87e2 + languageName: node + linkType: hard + +"path-exists@npm:^4.0.0": + version: 4.0.0 + resolution: "path-exists@npm:4.0.0" + checksum: 10/505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 + languageName: node + linkType: hard + +"path-is-absolute@npm:^1.0.0": + version: 1.0.1 + resolution: "path-is-absolute@npm:1.0.1" + checksum: 10/060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 + languageName: node + linkType: hard + +"path-key@npm:^3.0.0, path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" checksum: 10/55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 languageName: node linkType: hard +"path-parse@npm:^1.0.7": + version: 1.0.7 + resolution: "path-parse@npm:1.0.7" + checksum: 10/49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a + languageName: node + linkType: hard + "path-scurry@npm:^1.11.1": version: 1.11.1 resolution: "path-scurry@npm:1.11.1" @@ -1655,6 +3803,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^2.0.4, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 10/60c2595003b05e4535394d1da94850f5372c9427ca4413b71210f437f7b2ca091dbd611c45e8b37d10036fa8eade25c1b8951654f9d3973bfa66a2ff4d3b08bc + languageName: node + linkType: hard + "picomatch@npm:^4.0.2": version: 4.0.2 resolution: "picomatch@npm:4.0.2" @@ -1662,6 +3817,22 @@ __metadata: languageName: node linkType: hard +"pirates@npm:^4.0.4": + version: 4.0.7 + resolution: "pirates@npm:4.0.7" + checksum: 10/2427f371366081ae42feb58214f04805d6b41d6b84d74480ebcc9e0ddbd7105a139f7c653daeaf83ad8a1a77214cf07f64178e76de048128fec501eab3305a96 + languageName: node + linkType: hard + +"pkg-dir@npm:^4.2.0": + version: 4.2.0 + resolution: "pkg-dir@npm:4.2.0" + dependencies: + find-up: "npm:^4.0.0" + checksum: 10/9863e3f35132bf99ae1636d31ff1e1e3501251d480336edb1c211133c8d58906bed80f154a1d723652df1fda91e01c7442c2eeaf9dc83157c7ae89087e43c8d6 + languageName: node + linkType: hard + "postcss@npm:^8.5.3": version: 8.5.3 resolution: "postcss@npm:8.5.3" @@ -1673,6 +3844,17 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": + version: 29.7.0 + resolution: "pretty-format@npm:29.7.0" + dependencies: + "@jest/schemas": "npm:^29.6.3" + ansi-styles: "npm:^5.0.0" + react-is: "npm:^18.0.0" + checksum: 10/dea96bc83c83cd91b2bfc55757b6b2747edcaac45b568e46de29deee80742f17bc76fe8898135a70d904f4928eafd8bb693cd1da4896e8bdd3c5e82cadf1d2bb + languageName: node + linkType: hard + "proc-log@npm:^5.0.0": version: 5.0.0 resolution: "proc-log@npm:5.0.0" @@ -1690,13 +3872,86 @@ __metadata: languageName: node linkType: hard -"pure-rand@npm:^6.1.0": +"prompts@npm:^2.0.1": + version: 2.4.2 + resolution: "prompts@npm:2.4.2" + dependencies: + kleur: "npm:^3.0.3" + sisteransi: "npm:^1.0.5" + checksum: 10/c52536521a4d21eff4f2f2aa4572446cad227464066365a7167e52ccf8d9839c099f9afec1aba0eed3d5a2514b3e79e0b3e7a1dc326b9acde6b75d27ed74b1a9 + languageName: node + linkType: hard + +"pure-rand@npm:^6.0.0, pure-rand@npm:^6.1.0": version: 6.1.0 resolution: "pure-rand@npm:6.1.0" checksum: 10/256aa4bcaf9297256f552914e03cbdb0039c8fe1db11fa1e6d3f80790e16e563eb0a859a1e61082a95e224fc0c608661839439f8ecc6a3db4e48d46d99216ee4 languageName: node linkType: hard +"react-is@npm:^18.0.0": + version: 18.3.1 + resolution: "react-is@npm:18.3.1" + checksum: 10/d5f60c87d285af24b1e1e7eaeb123ec256c3c8bdea7061ab3932e3e14685708221bf234ec50b21e10dd07f008f1b966a2730a0ce4ff67905b3872ff2042aec22 + languageName: node + linkType: hard + +"require-directory@npm:^2.1.1": + version: 2.1.1 + resolution: "require-directory@npm:2.1.1" + checksum: 10/a72468e2589270d91f06c7d36ec97a88db53ae5d6fe3787fadc943f0b0276b10347f89b363b2a82285f650bdcc135ad4a257c61bdd4d00d6df1fa24875b0ddaf + languageName: node + linkType: hard + +"resolve-cwd@npm:^3.0.0": + version: 3.0.0 + resolution: "resolve-cwd@npm:3.0.0" + dependencies: + resolve-from: "npm:^5.0.0" + checksum: 10/546e0816012d65778e580ad62b29e975a642989108d9a3c5beabfb2304192fa3c9f9146fbdfe213563c6ff51975ae41bac1d3c6e047dd9572c94863a057b4d81 + languageName: node + linkType: hard + +"resolve-from@npm:^5.0.0": + version: 5.0.0 + resolution: "resolve-from@npm:5.0.0" + checksum: 10/be18a5e4d76dd711778664829841cde690971d02b6cbae277735a09c1c28f407b99ef6ef3cd585a1e6546d4097b28df40ed32c4a287b9699dcf6d7f208495e23 + languageName: node + linkType: hard + +"resolve.exports@npm:^2.0.0": + version: 2.0.3 + resolution: "resolve.exports@npm:2.0.3" + checksum: 10/536efee0f30a10fac8604e6cdc7844dbc3f4313568d09f06db4f7ed8a5b8aeb8585966fe975083d1f2dfbc87cf5f8bc7ab65a5c23385c14acbb535ca79f8398a + languageName: node + linkType: hard + +"resolve@npm:^1.20.0": + version: 1.22.10 + resolution: "resolve@npm:1.22.10" + dependencies: + is-core-module: "npm:^2.16.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10/0a398b44da5c05e6e421d70108822c327675febb880eebe905587628de401854c61d5df02866ff34fc4cb1173a51c9f0e84a94702738df3611a62e2acdc68181 + languageName: node + linkType: hard + +"resolve@patch:resolve@npm%3A^1.20.0#optional!builtin": + version: 1.22.10 + resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" + dependencies: + is-core-module: "npm:^2.16.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10/d4d878bfe3702d215ea23e75e0e9caf99468e3db76f5ca100d27ebdc527366fee3877e54bce7d47cc72ca8952fc2782a070d238bfa79a550eeb0082384c3b81a + languageName: node + linkType: hard + "restore-cursor@npm:^5.0.0": version: 5.1.0 resolution: "restore-cursor@npm:5.1.0" @@ -1813,7 +4068,16 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.5": +"semver@npm:^6.3.0, semver@npm:^6.3.1": + version: 6.3.1 + resolution: "semver@npm:6.3.1" + bin: + semver: bin/semver.js + checksum: 10/1ef3a85bd02a760c6ef76a45b8c1ce18226de40831e02a00bad78485390b98b6ccaa31046245fc63bba4a47a6a592b6c7eedc65cc47126e60489f9cc1ce3ed7e + languageName: node + linkType: hard + +"semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4": version: 7.7.2 resolution: "semver@npm:7.7.2" bin: @@ -1845,6 +4109,13 @@ __metadata: languageName: node linkType: hard +"signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": + version: 3.0.7 + resolution: "signal-exit@npm:3.0.7" + checksum: 10/a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 + languageName: node + linkType: hard + "signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" @@ -1852,6 +4123,20 @@ __metadata: languageName: node linkType: hard +"sisteransi@npm:^1.0.5": + version: 1.0.5 + resolution: "sisteransi@npm:1.0.5" + checksum: 10/aba6438f46d2bfcef94cf112c835ab395172c75f67453fe05c340c770d3c402363018ae1ab4172a1026a90c47eaccf3af7b6ff6fa749a680c2929bd7fa2b37a4 + languageName: node + linkType: hard + +"slash@npm:^3.0.0": + version: 3.0.0 + resolution: "slash@npm:3.0.0" + checksum: 10/94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c + languageName: node + linkType: hard + "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" @@ -1887,6 +4172,23 @@ __metadata: languageName: node linkType: hard +"source-map-support@npm:0.5.13": + version: 0.5.13 + resolution: "source-map-support@npm:0.5.13" + dependencies: + buffer-from: "npm:^1.0.0" + source-map: "npm:^0.6.0" + checksum: 10/d1514a922ac9c7e4786037eeff6c3322f461cd25da34bb9fefb15387b3490531774e6e31d95ab6d5b84a3e139af9c3a570ccaee6b47bd7ea262691ed3a8bc34e + languageName: node + linkType: hard + +"source-map@npm:^0.6.0, source-map@npm:^0.6.1": + version: 0.6.1 + resolution: "source-map@npm:0.6.1" + checksum: 10/59ef7462f1c29d502b3057e822cdbdae0b0e565302c4dd1a95e11e793d8d9d62006cdc10e0fd99163ca33ff2071360cf50ee13f90440806e7ed57d81cba2f7ff + languageName: node + linkType: hard + "sprintf-js@npm:^1.1.3": version: 1.1.3 resolution: "sprintf-js@npm:1.1.3" @@ -1894,6 +4196,13 @@ __metadata: languageName: node linkType: hard +"sprintf-js@npm:~1.0.2": + version: 1.0.3 + resolution: "sprintf-js@npm:1.0.3" + checksum: 10/c34828732ab8509c2741e5fd1af6b767c3daf2c642f267788f933a65b1614943c282e74c4284f4fa749c264b18ee016a0d37a3e5b73aee446da46277d3a85daa + languageName: node + linkType: hard + "ssri@npm:^12.0.0": version: 12.0.0 resolution: "ssri@npm:12.0.0" @@ -1903,6 +4212,15 @@ __metadata: languageName: node linkType: hard +"stack-utils@npm:^2.0.3": + version: 2.0.6 + resolution: "stack-utils@npm:2.0.6" + dependencies: + escape-string-regexp: "npm:^2.0.0" + checksum: 10/cdc988acbc99075b4b036ac6014e5f1e9afa7e564482b687da6384eee6a1909d7eaffde85b0a17ffbe186c5247faf6c2b7544e802109f63b72c7be69b13151bb + languageName: node + linkType: hard + "stackback@npm:0.0.2": version: 0.0.2 resolution: "stackback@npm:0.0.2" @@ -1924,7 +4242,17 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": +"string-length@npm:^4.0.1": + version: 4.0.2 + resolution: "string-length@npm:4.0.2" + dependencies: + char-regex: "npm:^1.0.2" + strip-ansi: "npm:^6.0.0" + checksum: 10/ce85533ef5113fcb7e522bcf9e62cb33871aa99b3729cec5595f4447f660b0cefd542ca6df4150c97a677d58b0cb727a3fe09ac1de94071d05526c73579bf505 + languageName: node + linkType: hard + +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -1975,6 +4303,52 @@ __metadata: languageName: node linkType: hard +"strip-bom@npm:^4.0.0": + version: 4.0.0 + resolution: "strip-bom@npm:4.0.0" + checksum: 10/9dbcfbaf503c57c06af15fe2c8176fb1bf3af5ff65003851a102749f875a6dbe0ab3b30115eccf6e805e9d756830d3e40ec508b62b3f1ddf3761a20ebe29d3f3 + languageName: node + linkType: hard + +"strip-final-newline@npm:^2.0.0": + version: 2.0.0 + resolution: "strip-final-newline@npm:2.0.0" + checksum: 10/69412b5e25731e1938184b5d489c32e340605bb611d6140344abc3421b7f3c6f9984b21dff296dfcf056681b82caa3bb4cc996a965ce37bcfad663e92eae9c64 + languageName: node + linkType: hard + +"strip-json-comments@npm:^3.1.1": + version: 3.1.1 + resolution: "strip-json-comments@npm:3.1.1" + checksum: 10/492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 + languageName: node + linkType: hard + +"supports-color@npm:^7.1.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 10/c8bb7afd564e3b26b50ca6ee47572c217526a1389fe018d00345856d4a9b08ffbd61fadaf283a87368d94c3dcdb8f5ffe2650a5a65863e21ad2730ca0f05210a + languageName: node + linkType: hard + +"supports-color@npm:^8.0.0": + version: 8.1.1 + resolution: "supports-color@npm:8.1.1" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 10/157b534df88e39c5518c5e78c35580c1eca848d7dbaf31bbe06cdfc048e22c7ff1a9d046ae17b25691128f631a51d9ec373c1b740c12ae4f0de6e292037e4282 + languageName: node + linkType: hard + +"supports-preserve-symlinks-flag@npm:^1.0.0": + version: 1.0.0 + resolution: "supports-preserve-symlinks-flag@npm:1.0.0" + checksum: 10/a9dc19ae2220c952bd2231d08ddeecb1b0328b61e72071ff4000c8384e145cc07c1c0bdb3b5a1cb06e186a7b2790f1dee793418b332f6ddf320de25d9125be7e + languageName: node + linkType: hard + "tar@npm:^7.4.3": version: 7.4.3 resolution: "tar@npm:7.4.3" @@ -1989,6 +4363,17 @@ __metadata: languageName: node linkType: hard +"test-exclude@npm:^6.0.0": + version: 6.0.0 + resolution: "test-exclude@npm:6.0.0" + dependencies: + "@istanbuljs/schema": "npm:^0.1.2" + glob: "npm:^7.1.4" + minimatch: "npm:^3.0.4" + checksum: 10/8fccb2cb6c8fcb6bb4115394feb833f8b6cf4b9503ec2485c2c90febf435cac62abe882a0c5c51a37b9bbe70640cdd05acf5f45e486ac4583389f4b0855f69e5 + languageName: node + linkType: hard + "tinybench@npm:^2.9.0": version: 2.9.0 resolution: "tinybench@npm:2.9.0" @@ -2034,6 +4419,22 @@ __metadata: languageName: node linkType: hard +"tmpl@npm:1.0.5": + version: 1.0.5 + resolution: "tmpl@npm:1.0.5" + checksum: 10/cd922d9b853c00fe414c5a774817be65b058d54a2d01ebb415840960406c669a0fc632f66df885e24cb022ec812739199ccbdb8d1164c3e513f85bfca5ab2873 + languageName: node + linkType: hard + +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: "npm:^7.0.0" + checksum: 10/10dda13571e1f5ad37546827e9b6d4252d2e0bc176c24a101252153ef435d83696e2557fe128c4678e4e78f5f01e83711c703eef9814eb12dab028580d45980a + languageName: node + linkType: hard + "ts-node@npm:^10.9.2": version: 10.9.2 resolution: "ts-node@npm:10.9.2" @@ -2143,6 +4544,20 @@ __metadata: languageName: node linkType: hard +"type-detect@npm:4.0.8": + version: 4.0.8 + resolution: "type-detect@npm:4.0.8" + checksum: 10/5179e3b8ebc51fce1b13efb75fdea4595484433f9683bbc2dca6d99789dba4e602ab7922d2656f2ce8383987467f7770131d4a7f06a26287db0615d2f4c4ce7d + languageName: node + linkType: hard + +"type-fest@npm:^0.21.3": + version: 0.21.3 + resolution: "type-fest@npm:0.21.3" + checksum: 10/f4254070d9c3d83a6e573bcb95173008d73474ceadbbf620dd32d273940ca18734dff39c2b2480282df9afe5d1675ebed5499a00d791758748ea81f61a38961f + languageName: node + linkType: hard + "typescript@npm:^5.2.2, typescript@npm:^5.8.2": version: 5.8.3 resolution: "typescript@npm:5.8.3" @@ -2195,6 +4610,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.1.3": + version: 1.1.3 + resolution: "update-browserslist-db@npm:1.1.3" + dependencies: + escalade: "npm:^3.2.0" + picocolors: "npm:^1.1.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10/87af2776054ffb9194cf95e0201547d041f72ee44ce54b144da110e65ea7ca01379367407ba21de5c9edd52c74d95395366790de67f3eb4cc4afa0fe4424e76f + languageName: node + linkType: hard + "v8-compile-cache-lib@npm:^3.0.1": version: 3.0.1 resolution: "v8-compile-cache-lib@npm:3.0.1" @@ -2202,6 +4631,17 @@ __metadata: languageName: node linkType: hard +"v8-to-istanbul@npm:^9.0.1": + version: 9.3.0 + resolution: "v8-to-istanbul@npm:9.3.0" + dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.12" + "@types/istanbul-lib-coverage": "npm:^2.0.1" + convert-source-map: "npm:^2.0.0" + checksum: 10/fb1d70f1176cb9dc46cabbb3fd5c52c8f3e8738b61877b6e7266029aed0870b04140e3f9f4550ac32aebcfe1d0f38b0bac57e1e8fb97d68fec82f2b416148166 + languageName: node + linkType: hard + "vite-node@npm:3.1.3": version: 3.1.3 resolution: "vite-node@npm:3.1.3" @@ -2326,6 +4766,15 @@ __metadata: languageName: node linkType: hard +"walker@npm:^1.0.8": + version: 1.0.8 + resolution: "walker@npm:1.0.8" + dependencies: + makeerror: "npm:1.0.12" + checksum: 10/ad7a257ea1e662e57ef2e018f97b3c02a7240ad5093c392186ce0bcf1f1a60bbadd520d073b9beb921ed99f64f065efb63dfc8eec689a80e569f93c1c5d5e16c + languageName: node + linkType: hard + "which@npm:^2.0.1": version: 2.0.2 resolution: "which@npm:2.0.2" @@ -2360,7 +4809,7 @@ __metadata: languageName: node linkType: hard -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" dependencies: @@ -2382,6 +4831,37 @@ __metadata: languageName: node linkType: hard +"wrappy@npm:1": + version: 1.0.2 + resolution: "wrappy@npm:1.0.2" + checksum: 10/159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 + languageName: node + linkType: hard + +"write-file-atomic@npm:^4.0.2": + version: 4.0.2 + resolution: "write-file-atomic@npm:4.0.2" + dependencies: + imurmurhash: "npm:^0.1.4" + signal-exit: "npm:^3.0.7" + checksum: 10/3be1f5508a46c190619d5386b1ac8f3af3dbe951ed0f7b0b4a0961eed6fc626bd84b50cf4be768dabc0a05b672f5d0c5ee7f42daa557b14415d18c3a13c7d246 + languageName: node + linkType: hard + +"y18n@npm:^5.0.5": + version: 5.0.8 + resolution: "y18n@npm:5.0.8" + checksum: 10/5f1b5f95e3775de4514edbb142398a2c37849ccfaf04a015be5d75521e9629d3be29bd4432d23c57f37e5b61ade592fb0197022e9993f81a06a5afbdcda9346d + languageName: node + linkType: hard + +"yallist@npm:^3.0.2": + version: 3.1.1 + resolution: "yallist@npm:3.1.1" + checksum: 10/9af0a4329c3c6b779ac4736c69fae4190ac03029fa27c1aef4e6bcc92119b73dea6fe5db5fe881fb0ce2a0e9539a42cdf60c7c21eda04d1a0b8c082e38509efb + languageName: node + linkType: hard + "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" @@ -2396,6 +4876,28 @@ __metadata: languageName: node linkType: hard +"yargs-parser@npm:^21.1.1": + version: 21.1.1 + resolution: "yargs-parser@npm:21.1.1" + checksum: 10/9dc2c217ea3bf8d858041252d43e074f7166b53f3d010a8c711275e09cd3d62a002969a39858b92bbda2a6a63a585c7127014534a560b9c69ed2d923d113406e + languageName: node + linkType: hard + +"yargs@npm:^17.3.1": + version: 17.7.2 + resolution: "yargs@npm:17.7.2" + dependencies: + cliui: "npm:^8.0.1" + escalade: "npm:^3.1.1" + get-caller-file: "npm:^2.0.5" + require-directory: "npm:^2.1.1" + string-width: "npm:^4.2.3" + y18n: "npm:^5.0.5" + yargs-parser: "npm:^21.1.1" + checksum: 10/abb3e37678d6e38ea85485ed86ebe0d1e3464c640d7d9069805ea0da12f69d5a32df8e5625e370f9c96dd1c2dc088ab2d0a4dd32af18222ef3c4224a19471576 + languageName: node + linkType: hard + "yn@npm:3.1.1": version: 3.1.1 resolution: "yn@npm:3.1.1" @@ -2403,6 +4905,13 @@ __metadata: languageName: node linkType: hard +"yocto-queue@npm:^0.1.0": + version: 0.1.0 + resolution: "yocto-queue@npm:0.1.0" + checksum: 10/f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 + languageName: node + linkType: hard + "yoctocolors@npm:^2.1.1": version: 2.1.1 resolution: "yoctocolors@npm:2.1.1" From aff73f4cf080f7c72b10e0a70b9d0546b9e07962 Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 18 May 2025 20:49:34 -0500 Subject: [PATCH 101/282] change field to uint<128> --- contracts/erc721/src/ERC721.compact | 328 ------------------ .../erc721/src/test/mocks/MockERC721.compact | 152 -------- 2 files changed, 480 deletions(-) delete mode 100644 contracts/erc721/src/ERC721.compact delete mode 100644 contracts/erc721/src/test/mocks/MockERC721.compact diff --git a/contracts/erc721/src/ERC721.compact b/contracts/erc721/src/ERC721.compact deleted file mode 100644 index 320ecf07..00000000 --- a/contracts/erc721/src/ERC721.compact +++ /dev/null @@ -1,328 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.15.0; - -/** - * @module ERC721 - * @description An unshielded ERC721 library. - * - * @notice ADD - * - * @notice Further discussion and consideration required: - * - * - Consider changing the underscore in the internal methods to `unsafe` or - * adopting dot notation for prefixing imports. - * - Revise logic once contract-to-contract interactions are available on midnight. - * - Consider implementing an introspection mechanism for transfers to contracts. - * - Standardize which zero address to use (`ZswapCoinPublicKey` or `ContractAddress`). - */ -module ERC721 { - import CompactStandardLibrary; - import "../../node_modules/@openzeppelin-midnight/utils/src/Utils" prefix Utils_; - - /// Public state - export sealed ledger _name: Maybe>; - export sealed ledger _symbol: Maybe>; - export ledger _owners: Map>; - export ledger _balances: Map, Uint<128>>; - export ledger _tokenApprovals: Map>; - export ledger _operatorApprovals: Map, Map, Boolean>>; - - /// Private state - /** - * @description Computes a tokenURI given a `baseURI` and `tokenId` - * - * @param baseURI - baseURI of the final tokenURI, defaults to the empty string - * @param tokenId - The token identifier - * - * @return {Opaque<"string">} - The final URI of the provided token identifier - */ - witness computeTokenURI(baseURI: Opaque<"string">, tokenId: Field): Opaque<"string">; - - /** - * @description Initializes the contract by setting the name and symbol. - * - * @param name_ - The name of the token. - * @param symbol_ - The symbol of the token. - */ - export circuit initializer( - name_: Maybe>, - symbol_: Maybe> - ): [] { - _name = name_; - _symbol = symbol_; - } - - /** - * @description Returns the token name. - * - * @return {Maybe>} - The token name. - */ - export circuit name(): Maybe> { - return _name; - } - - /** - * @description Returns the symbol of the token. - * - * @return {Maybe>} - The token name. - */ - export circuit symbol(): Maybe> { - return _symbol; - } - - - /** - * @description Returns the value of tokens owned by `account`. - * - * @dev Manually checks if `account` is a key in the map and returns 0 if it is not. - * - * @param {account} - The public key to query. - * @return {Uint<128>} - The account's token balance. - */ - export circuit balanceOf(account: ZswapCoinPublicKey): Uint<128> { - const acct = left(account); - if (!_balances.member(acct)) { - return 0; - } - - return _balances.lookup(acct); - } - - /** - * @description Returns the owner of the `tokenId` token. - * - * @dev Tokens assigned to zero address are considered invalid, and queries about them do throw. - * - * @param {tokenId} - The identifier for a token. - * @return {ZswapCoinPublicKey} - The public key that owns the token. - */ - export circuit ownerOf(tokenId: Field): ZswapCoinPublicKey { - return _requireOwned(tokenId).left; - } - - export circuit tokenURI(tokenId: Field): Opaque<"string"> { - _requireOwned(tokenId); - - const baseURI = _baseURI(); - return disclose(computeTokenURI(baseURI, tokenId)); - } - - export circuit _baseURI(): Opaque<"string"> { - return default>; - } - - export circuit approve( - to: ZswapCoinPublicKey, - tokenId: Field - ): [] { - // TMP - Waiting for contract-to-contract calls to handle `right` with contract address - const auth = left(own_public_key()); - _approve( - left(to), - tokenId, - auth - ); - } - - export circuit getApproved(tokenId: Field): ZswapCoinPublicKey { - _requireOwned(tokenId); - - return _getApproved(tokenId).left; - } - - export circuit setApprovalForAll( - operator: ZswapCoinPublicKey, - approved: Boolean - ): [] { - // TMP - Waiting for contract-to-contract calls to handle `right` with contract address - const owner = left(own_public_key()); - _setApprovalForAll( - owner, - left(operator), - approved - ); - } - - export circuit isApprovedForAll( - owner: ZswapCoinPublicKey, - operator: ZswapCoinPublicKey - ): Boolean { - const eitherOwner = left(owner); - const eitherOperator = left(operator); - if (_operatorApprovals.member(eitherOwner) && _operatorApprovals.lookup(eitherOwner).member(eitherOperator)) { - return _operatorApprovals.lookup(eitherOwner).lookup(eitherOperator); - } else { - return false; - } - } - - export circuit transferFrom( - from: ZswapCoinPublicKey, - to: ZswapCoinPublicKey, - tokenId: Field - ): [] { - const eitherTo = left(to); - const eitherFrom = left(from); - assert !Utils_isKeyOrAddressZero(eitherTo) "ERC721: Invalid Receiver"; - // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists - // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. - - // Assumes sender is a ZSwapPublicKey - // Need to revisit once we have contract <> contract communication - const previousOwner = _update( - eitherTo, - tokenId, - left(own_public_key()) - ); - assert previousOwner != eitherFrom "ERC721: Incorrect Owner"; - } - - export circuit _requireOwned(tokenId: Field): Either { - assert _owners.member(tokenId) "ERC721: Nonexistent Token"; - const owner = _owners.lookup(tokenId); - - assert !Utils_isKeyOrAddressZero(owner) "ERC721: Invalid Owner"; - return owner; - } - - export circuit _ownerOf(tokenId: Field): Either { - if (!_owners.member(tokenId)) { - _owners.insert(tokenId, burn_address()); - } - - return _owners.lookup(tokenId); - } - - export circuit _update( - to: Either, - tokenId: Field, - auth: Either - ): Either { - const from = _ownerOf(tokenId); - - // Perform (optional) operator check - if (!Utils_isKeyOrAddressZero(auth)) { - _checkAuthorized(from, auth, tokenId); - } - - // execute update - if (!Utils_isKeyOrAddressZero(from)) { - // assuming burn address == zero address - // Need to test to confirm - _approve(burn_address(), tokenId, burn_address()); - const newBalance = _balances.lookup(from) - 1 as Uint<128>; - _balances.insert(from, newBalance); - } - - if (!Utils_isKeyOrAddressZero(to)) { - if (!_balances.member(to)) { - _balances.insert(to, 0); - } - const newBalance = _balances.lookup(to) + 1 as Uint<128>; - _balances.insert(to, newBalance); - } - - _owners.insert(tokenId, to); - - return from; - } - - export circuit _approve( - to: Either, - tokenId: Field, - auth: Either - ): [] { - if (!Utils_isKeyOrAddressZero(auth)) { - const owner = _requireOwned(tokenId); - - // We do not use _isAuthorized because single-token approvals should not be able to call approve - assert (!Utils_isKeyOrAddressZero(auth) && owner != auth && !isApprovedForAll(owner.left, auth.left)) "ERC721 Invalid Approver"; - } - - _tokenApprovals.insert(tokenId, to); - } - - export circuit _checkAuthorized( - owner: Either, - spender: Either, - tokenId: Field - ): [] { - if (!_isAuthorized(owner, spender, tokenId)) { - assert !Utils_isKeyOrAddressZero(owner) "ERC721: Nonexistent Token"; - assert false "ERC721: Insufficient Approval"; - } - } - - export circuit _isAuthorized( - owner: Either, - spender: Either, - tokenId: Field - ): Boolean { - return (!Utils_isKeyOrAddressZero(spender) && (owner == spender || isApprovedForAll(owner.left, spender.left) || _getApproved(tokenId) == spender)); - } - - export circuit _getApproved(tokenId: Field): Either { - // I think this returns the 0 address if token doesn't exist - // Make sure this doesn't cause problem in testing - return _tokenApprovals.lookup(tokenId); - } - - export circuit _setApprovalForAll( - owner: Either, - operator: Either, - approved: Boolean - ): [] { - assert !Utils_isKeyOrAddressZero(operator) "ERC721: Invalid Operator"; - - if (!_operatorApprovals.member(owner)) { - _operatorApprovals.insert( - owner, - default, Boolean>> - ); - _operatorApprovals.lookup(owner).insert(operator, approved); - } else { - _operatorApprovals.lookup(owner).insert(operator, approved); - } - } - - export circuit _increaseBalance( - account: Either, - value: Uint<128> - ): [] { - const newValue = _balances.lookup(account) + value; - _balances.insert(account, newValue as Uint<128>); - } - - export circuit _mint( - to: Either, - tokenId: Field - ): [] { - assert !Utils_isKeyOrAddressZero(to) "ERC721: Invalid Receiver"; - - // Assumes burn_address == zero address - // May want to define as default - const previousOwner = _update(to, tokenId, burn_address()); - - assert Utils_isKeyOrAddressZero(previousOwner) "ERC721: Invalid Sender"; - } - - export circuit _burn(tokenId: Field): [] { - const previousOwner = _update(burn_address(), tokenId, burn_address()); - assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Nonexistent Token"; - } - - export circuit _transfer( - from: Either, - to: Either, - tokenId: Field - ): [] { - assert !Utils_isKeyOrAddressZero(to) "ERC721: Invalid Receiver"; - - const previousOwner = _update(to, tokenId, burn_address()); - - assert !Utils_isKeyOrAddressZero(previousOwner) "ERC721: Nonexistent Token"; - assert previousOwner != from "ERC721: Incorrect Owner"; - } -} - diff --git a/contracts/erc721/src/test/mocks/MockERC721.compact b/contracts/erc721/src/test/mocks/MockERC721.compact deleted file mode 100644 index a979229e..00000000 --- a/contracts/erc721/src/test/mocks/MockERC721.compact +++ /dev/null @@ -1,152 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.15.0; - -import CompactStandardLibrary; - -import "../../ERC721" prefix ERC721_; - -export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; - -constructor( - _name: Maybe>, - _symbol: Maybe> -) { - ERC721_initializer(_name, _symbol); -} - -export circuit name(): Maybe> { - return ERC721_name(); -} - -export circuit symbol(): Maybe> { - return ERC721_symbol(); -} - -export circuit balanceOf(account: ZswapCoinPublicKey): Uint<128> { - return ERC721_balanceOf(account); -} - -export circuit ownerOf(tokenId: Field): ZswapCoinPublicKey { - return ERC721_ownerOf(tokenId); -} - -export circuit tokenURI(tokenId: Field): Opaque<"string"> { - return ERC721_tokenURI(tokenId); -} - -export circuit approve( - to: ZswapCoinPublicKey, - tokenId: Field -): [] { - return ERC721_approve(to, tokenId); -} - -export circuit getApproved(tokenId: Field): ZswapCoinPublicKey { - return ERC721_getApproved(tokenId); -} - -export circuit setApprovalForAll( - operator: ZswapCoinPublicKey, - approved: Boolean -): [] { - return ERC721_setApprovalForAll(operator, approved); -} - -export circuit isApprovedForAll( - owner: ZswapCoinPublicKey, - operator: ZswapCoinPublicKey -): Boolean { - return ERC721_isApprovedForAll(owner, operator); -} - -export circuit transferFrom( - from: ZswapCoinPublicKey, - to: ZswapCoinPublicKey, - tokenId: Field -): [] { - return ERC721_transferFrom(from, to, tokenId); -} - -export circuit _requireOwned(tokenId: Field): Either { - return ERC721__requireOwned(tokenId); -} - -export circuit _ownerOf(tokenId: Field): Either { - return ERC721__ownerOf(tokenId); -} - -export circuit _update( - to: Either, - tokenId: Field, - auth: Either -): Either { - return ERC721__update(to, tokenId, auth); -} - -export circuit _approve( - to: Either, - tokenId: Field, - auth: Either -): [] { - return ERC721__approve(to, tokenId, auth); -} - -export circuit _checkAuthorized( - owner: Either, - spender: Either, - tokenId: Field -): [] { - return ERC721__checkAuthorized(owner, spender, tokenId); -} - -export circuit _isAuthorized( - owner: Either, - spender: Either, - tokenId: Field -): Boolean { - return ERC721__isAuthorized(owner, spender, tokenId); -} - - -export circuit _getApproved(tokenId: Field): Either { - return ERC721__getApproved(tokenId); -} - -export circuit _setApprovalForAll( - owner: Either, - operator: Either, - approved: Boolean -): [] { - return ERC721__setApprovalForAll(owner, operator, approved); -} - -export circuit _increaseBalance( - account: Either, - value: Uint<128> -): [] { - return ERC721__increaseBalance(account, value); -} - -export circuit _mint( - to: Either, - tokenId: Field -): [] { - return ERC721__mint(to, tokenId); -} - -export circuit _burn(tokenId: Field): [] { - return ERC721__burn(tokenId); -} - -export circuit _transfer( - from: Either, - to: Either, - tokenId: Field -): [] { - return ERC721__transfer(from, to, tokenId); -} - -export circuit _baseURI(): Opaque<"string"> { - return ERC721__baseURI(); -} \ No newline at end of file From 7ac005833de7965e7915007d8be9ec601716b562 Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 18 May 2025 21:35:07 -0500 Subject: [PATCH 102/282] fix simulator methods --- .../src/test/simulators/ERC721Simulator.ts | 197 ------------------ 1 file changed, 197 deletions(-) delete mode 100644 contracts/erc721/src/test/simulators/ERC721Simulator.ts diff --git a/contracts/erc721/src/test/simulators/ERC721Simulator.ts b/contracts/erc721/src/test/simulators/ERC721Simulator.ts deleted file mode 100644 index 7fb6eed7..00000000 --- a/contracts/erc721/src/test/simulators/ERC721Simulator.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { - type CircuitContext, - type ContractState, - QueryContext, - constructorContext, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; -import { - type Ledger, - Contract as MockERC721, - ledger, - type Either, - type ZswapCoinPublicKey, - type ContractAddress, - pureCircuits -} from '../../artifacts/MockERC721/contract/index.cjs'; // Combined imports -import type { MaybeString } from '../types/string'; -import type { IContractSimulator } from '../types/test'; -import { type ERC721PrivateState, ERC721Witnesses } from '../../witnesses/ERC721Witnesses'; - -/** - * @description A simulator implementation of an ERC721 contract for testing purposes. - * @template P - The private state type, fixed to ERC721PrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. - */ -export class ERC721Simulator - implements IContractSimulator { - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockERC721; - - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor(name: MaybeString, symbol: MaybeString) { - this.contract = new MockERC721( - ERC721Witnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState( - constructorContext({ tokenURI: "https://www.mynft.test/" }, '0'.repeat(64)), name, symbol, - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type ERC721PrivateState. - */ - public getCurrentPrivateState(): ERC721PrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; - } - - /** - * @description Returns the token name. - * @returns The token name. - */ - public name(): MaybeString { - return this.contract.impureCircuits.name(this.circuitContext).result; - } - - /** - * @description Returns the symbol of the token. - * @returns The token name. - */ - public symbol(): MaybeString { - return this.contract.impureCircuits.symbol(this.circuitContext).result; - } - - /** - * @description Returns the value of tokens owned by `account`. - * @param account The public key or contract address to query. - * @returns The account's token balance. - */ - public balanceOf(account: ZswapCoinPublicKey): bigint { - return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; - } - - /** - * @description Returns the owner of `tokenId`. - * @param tokenId The Id of the token to query. - * @returns The account owner of the token. - */ - public ownerOf(tokenId: bigint): ZswapCoinPublicKey { - return this.contract.impureCircuits.ownerOf(this.circuitContext, tokenId).result; - } - - public tokenURI(tokenId: bigint): string { - return this.contract.impureCircuits.tokenURI(this.circuitContext, tokenId).result; - } - - public _baseURI(): string { - return pureCircuits._baseURI(); - } - - public approve(to: ZswapCoinPublicKey, tokenId: bigint): [] { - return this.contract.impureCircuits.approve(this.circuitContext, to, tokenId).result; - } - - public getApproved(tokenId: bigint): ZswapCoinPublicKey { - return this.contract.impureCircuits.getApproved(this.circuitContext, tokenId).result; - } - - public setApprovalForAll(operator: ZswapCoinPublicKey, approved: boolean): [] { - return this.contract.impureCircuits.setApprovalForAll(this.circuitContext, operator, approved).result; - } - - public isApprovedForAll(owner: ZswapCoinPublicKey, operator: ZswapCoinPublicKey): boolean { - return this.contract.impureCircuits.isApprovedForAll(this.circuitContext, owner, operator).result; - } - - public transferFrom(from: ZswapCoinPublicKey, to: ZswapCoinPublicKey, tokenId: bigint): [] { - return this.contract.impureCircuits.transferFrom(this.circuitContext, from, to, tokenId).result; - } - - public _requireOwned(tokenId: bigint): Either { - return this.contract.impureCircuits._requireOwned(this.circuitContext, tokenId).result; - } - - public _ownerOf(tokenId: bigint): Either { - return this.contract.impureCircuits._ownerOf(this.circuitContext, tokenId).result; - } - - public _update(to: Either, tokenId: bigint, auth: Either): Either { - return this.contract.impureCircuits._update(this.circuitContext, to, tokenId, auth).result; - } - - public _approve(to: Either, tokenId: bigint, auth: Either): [] { - return this.contract.impureCircuits._approve(this.circuitContext, to, tokenId, auth).result; - } - - public _checkAuthorized(owner: Either, spender: Either, tokenId: bigint): [] { - return this.contract.impureCircuits._checkAuthorized(this.circuitContext, owner, spender, tokenId).result; - } - - public _isAuthorized(owner: Either, spender: Either, tokenId: bigint): boolean { - return this.contract.impureCircuits._isAuthorized(this.circuitContext, owner, spender, tokenId).result; - } - - public _getApproved(tokenId: bigint): Either { - return this.contract.impureCircuits._getApproved(this.circuitContext, tokenId).result; - } - - public _setApprovalForAll(owner: Either, operator: Either, approved: boolean): [] { - return this.contract.impureCircuits._setApprovalForAll(this.circuitContext, owner, operator, approved).result; - } - - public _increaseBalance(account: Either, value: bigint): [] { - return this.contract.impureCircuits._increaseBalance(this.circuitContext, account, value).result; - } - - public _mint(to: Either, tokenId: bigint): [] { - return this.contract.impureCircuits._mint(this.circuitContext, to, tokenId).result; - } - - public _burn(tokenId: bigint): [] { - return this.contract.impureCircuits._burn(this.circuitContext, tokenId).result; - } - - public _transfer(from: Either, to: Either, tokenId: bigint): [] { - return this.contract.impureCircuits._transfer(this.circuitContext, from, to, tokenId).result; - } -} - From 7c5e40affd40950dad9271a9afc0a4e14162c5bc Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 18 May 2025 21:35:38 -0500 Subject: [PATCH 103/282] update package.json and yarnlock --- yarn.lock | 2573 +---------------------------------------------------- 1 file changed, 21 insertions(+), 2552 deletions(-) diff --git a/yarn.lock b/yarn.lock index f0e98265..1fb38804 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,385 +5,6 @@ __metadata: version: 8 cacheKey: 10 -"@ampproject/remapping@npm:^2.2.0": - version: 2.3.0 - resolution: "@ampproject/remapping@npm:2.3.0" - dependencies: - "@jridgewell/gen-mapping": "npm:^0.3.5" - "@jridgewell/trace-mapping": "npm:^0.3.24" - checksum: 10/f3451525379c68a73eb0a1e65247fbf28c0cccd126d93af21c75fceff77773d43c0d4a2d51978fb131aff25b5f2cb41a9fe48cc296e61ae65e679c4f6918b0ab - languageName: node - linkType: hard - -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/code-frame@npm:7.27.1" - dependencies: - "@babel/helper-validator-identifier": "npm:^7.27.1" - js-tokens: "npm:^4.0.0" - picocolors: "npm:^1.1.1" - checksum: 10/721b8a6e360a1fa0f1c9fe7351ae6c874828e119183688b533c477aa378f1010f37cc9afbfc4722c686d1f5cdd00da02eab4ba7278a0c504fa0d7a321dcd4fdf - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.27.2": - version: 7.27.2 - resolution: "@babel/compat-data@npm:7.27.2" - checksum: 10/eaa9f8aaeb9475779f4411fa397f712a6441b650d4e0b40c5535c954c891cd35c0363004db42902192aa8224532ac31ce06890478b060995286fe4fadd54e542 - languageName: node - linkType: hard - -"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.23.9": - version: 7.27.1 - resolution: "@babel/core@npm:7.27.1" - dependencies: - "@ampproject/remapping": "npm:^2.2.0" - "@babel/code-frame": "npm:^7.27.1" - "@babel/generator": "npm:^7.27.1" - "@babel/helper-compilation-targets": "npm:^7.27.1" - "@babel/helper-module-transforms": "npm:^7.27.1" - "@babel/helpers": "npm:^7.27.1" - "@babel/parser": "npm:^7.27.1" - "@babel/template": "npm:^7.27.1" - "@babel/traverse": "npm:^7.27.1" - "@babel/types": "npm:^7.27.1" - convert-source-map: "npm:^2.0.0" - debug: "npm:^4.1.0" - gensync: "npm:^1.0.0-beta.2" - json5: "npm:^2.2.3" - semver: "npm:^6.3.1" - checksum: 10/3dfec88f84b3ce567e6c482db0119f02f451bd3f86b0835c71c029fedb657969786507fafedd3a0732bd1be9fbc9f0635d734efafabad6dbc67d3eb7b494cdd8 - languageName: node - linkType: hard - -"@babel/generator@npm:^7.27.1, @babel/generator@npm:^7.7.2": - version: 7.27.1 - resolution: "@babel/generator@npm:7.27.1" - dependencies: - "@babel/parser": "npm:^7.27.1" - "@babel/types": "npm:^7.27.1" - "@jridgewell/gen-mapping": "npm:^0.3.5" - "@jridgewell/trace-mapping": "npm:^0.3.25" - jsesc: "npm:^3.0.2" - checksum: 10/6101825922a8a116e64b507d9309b38c5bc027b333d7111fcb760422741d3c72bd8f8e5aa935c2944c434ffe376353a27afa3a25a8526dc2ef90743d266770db - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.27.1": - version: 7.27.2 - resolution: "@babel/helper-compilation-targets@npm:7.27.2" - dependencies: - "@babel/compat-data": "npm:^7.27.2" - "@babel/helper-validator-option": "npm:^7.27.1" - browserslist: "npm:^4.24.0" - lru-cache: "npm:^5.1.1" - semver: "npm:^6.3.1" - checksum: 10/bd53c30a7477049db04b655d11f4c3500aea3bcbc2497cf02161de2ecf994fec7c098aabbcebe210ffabc2ecbdb1e3ffad23fb4d3f18723b814f423ea1749fe8 - languageName: node - linkType: hard - -"@babel/helper-module-imports@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-module-imports@npm:7.27.1" - dependencies: - "@babel/traverse": "npm:^7.27.1" - "@babel/types": "npm:^7.27.1" - checksum: 10/58e792ea5d4ae71676e0d03d9fef33e886a09602addc3bd01388a98d87df9fcfd192968feb40ac4aedb7e287ec3d0c17b33e3ecefe002592041a91d8a1998a8d - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-module-transforms@npm:7.27.1" - dependencies: - "@babel/helper-module-imports": "npm:^7.27.1" - "@babel/helper-validator-identifier": "npm:^7.27.1" - "@babel/traverse": "npm:^7.27.1" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/415509a5854203073755aab3ad293664146a55777355b5b5187902f976162c9565907d2276f7f6e778527be4829db2d926015d446100a65f2538d6397d83e248 - languageName: node - linkType: hard - -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.27.1, @babel/helper-plugin-utils@npm:^7.8.0": - version: 7.27.1 - resolution: "@babel/helper-plugin-utils@npm:7.27.1" - checksum: 10/96136c2428888e620e2ec493c25888f9ceb4a21099dcf3dd4508ea64b58cdedbd5a9fb6c7b352546de84d6c24edafe482318646932a22c449ebd16d16c22d864 - languageName: node - linkType: hard - -"@babel/helper-string-parser@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-string-parser@npm:7.27.1" - checksum: 10/0ae29cc2005084abdae2966afdb86ed14d41c9c37db02c3693d5022fba9f5d59b011d039380b8e537c34daf117c549f52b452398f576e908fb9db3c7abbb3a00 - languageName: node - linkType: hard - -"@babel/helper-validator-identifier@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-validator-identifier@npm:7.27.1" - checksum: 10/75041904d21bdc0cd3b07a8ac90b11d64cd3c881e89cb936fa80edd734bf23c35e6bd1312611e8574c4eab1f3af0f63e8a5894f4699e9cfdf70c06fcf4252320 - languageName: node - linkType: hard - -"@babel/helper-validator-option@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-validator-option@npm:7.27.1" - checksum: 10/db73e6a308092531c629ee5de7f0d04390835b21a263be2644276cb27da2384b64676cab9f22cd8d8dbd854c92b1d7d56fc8517cf0070c35d1c14a8c828b0903 - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helpers@npm:7.27.1" - dependencies: - "@babel/template": "npm:^7.27.1" - "@babel/types": "npm:^7.27.1" - checksum: 10/b86ee2c87d52640c63ec1fdf139d4560efc173ae6379659e0df49a3c0cf1d5f24436132ebb4459a4ee72418b43b39ee001f4e01465b48c8d31911a745ec4fd74 - languageName: node - linkType: hard - -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.27.1, @babel/parser@npm:^7.27.2": - version: 7.27.2 - resolution: "@babel/parser@npm:7.27.2" - dependencies: - "@babel/types": "npm:^7.27.1" - bin: - parser: ./bin/babel-parser.js - checksum: 10/133b4ccfbc01d4f36b0945937aabff87026c29fda6dcd3c842053a672e50f2487a101a3acd150bbaa2eecd33f3bd35650f95b806567c926f93b2af35c2b615c9 - languageName: node - linkType: hard - -"@babel/plugin-syntax-async-generators@npm:^7.8.4": - version: 7.8.4 - resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/7ed1c1d9b9e5b64ef028ea5e755c0be2d4e5e4e3d6cf7df757b9a8c4cfa4193d268176d0f1f7fbecdda6fe722885c7fda681f480f3741d8a2d26854736f05367 - languageName: node - linkType: hard - -"@babel/plugin-syntax-bigint@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-bigint@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/3a10849d83e47aec50f367a9e56a6b22d662ddce643334b087f9828f4c3dd73bdc5909aaeabe123fed78515767f9ca43498a0e621c438d1cd2802d7fae3c9648 - languageName: node - linkType: hard - -"@babel/plugin-syntax-class-properties@npm:^7.12.13": - version: 7.12.13 - resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.12.13" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/24f34b196d6342f28d4bad303612d7ff566ab0a013ce89e775d98d6f832969462e7235f3e7eaf17678a533d4be0ba45d3ae34ab4e5a9dcbda5d98d49e5efa2fc - languageName: node - linkType: hard - -"@babel/plugin-syntax-class-static-block@npm:^7.14.5": - version: 7.14.5 - resolution: "@babel/plugin-syntax-class-static-block@npm:7.14.5" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.14.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/3e80814b5b6d4fe17826093918680a351c2d34398a914ce6e55d8083d72a9bdde4fbaf6a2dcea0e23a03de26dc2917ae3efd603d27099e2b98380345703bf948 - languageName: node - linkType: hard - -"@babel/plugin-syntax-import-attributes@npm:^7.24.7": - version: 7.27.1 - resolution: "@babel/plugin-syntax-import-attributes@npm:7.27.1" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.27.1" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/97973982fff1bbf86b3d1df13380567042887c50e2ae13a400d02a8ff2c9742a60a75e279bfb73019e1cd9710f04be5e6ab81f896e6678dcfcec8b135e8896cf - languageName: node - linkType: hard - -"@babel/plugin-syntax-import-meta@npm:^7.10.4": - version: 7.10.4 - resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.10.4" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/166ac1125d10b9c0c430e4156249a13858c0366d38844883d75d27389621ebe651115cb2ceb6dc011534d5055719fa1727b59f39e1ab3ca97820eef3dcab5b9b - languageName: node - linkType: hard - -"@babel/plugin-syntax-json-strings@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-json-strings@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/bf5aea1f3188c9a507e16efe030efb996853ca3cadd6512c51db7233cc58f3ac89ff8c6bdfb01d30843b161cfe7d321e1bf28da82f7ab8d7e6bc5464666f354a - languageName: node - linkType: hard - -"@babel/plugin-syntax-jsx@npm:^7.7.2": - version: 7.27.1 - resolution: "@babel/plugin-syntax-jsx@npm:7.27.1" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.27.1" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/c6d1324cff286a369aa95d99b8abd21dd07821b5d3affd5fe7d6058c84cff9190743287826463ee57a7beecd10fa1e4bc99061df532ee14e188c1c8937b13e3a - languageName: node - linkType: hard - -"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4": - version: 7.10.4 - resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.10.4" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/aff33577037e34e515911255cdbb1fd39efee33658aa00b8a5fd3a4b903585112d037cce1cc9e4632f0487dc554486106b79ccd5ea63a2e00df4363f6d4ff886 - languageName: node - linkType: hard - -"@babel/plugin-syntax-nullish-coalescing-operator@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-nullish-coalescing-operator@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/87aca4918916020d1fedba54c0e232de408df2644a425d153be368313fdde40d96088feed6c4e5ab72aac89be5d07fef2ddf329a15109c5eb65df006bf2580d1 - languageName: node - linkType: hard - -"@babel/plugin-syntax-numeric-separator@npm:^7.10.4": - version: 7.10.4 - resolution: "@babel/plugin-syntax-numeric-separator@npm:7.10.4" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.10.4" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/01ec5547bd0497f76cc903ff4d6b02abc8c05f301c88d2622b6d834e33a5651aa7c7a3d80d8d57656a4588f7276eba357f6b7e006482f5b564b7a6488de493a1 - languageName: node - linkType: hard - -"@babel/plugin-syntax-object-rest-spread@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-object-rest-spread@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/fddcf581a57f77e80eb6b981b10658421bc321ba5f0a5b754118c6a92a5448f12a0c336f77b8abf734841e102e5126d69110a306eadb03ca3e1547cab31f5cbf - languageName: node - linkType: hard - -"@babel/plugin-syntax-optional-catch-binding@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-optional-catch-binding@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/910d90e72bc90ea1ce698e89c1027fed8845212d5ab588e35ef91f13b93143845f94e2539d831dc8d8ededc14ec02f04f7bd6a8179edd43a326c784e7ed7f0b9 - languageName: node - linkType: hard - -"@babel/plugin-syntax-optional-chaining@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-optional-chaining@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/eef94d53a1453361553c1f98b68d17782861a04a392840341bc91780838dd4e695209c783631cf0de14c635758beafb6a3a65399846ffa4386bff90639347f30 - languageName: node - linkType: hard - -"@babel/plugin-syntax-private-property-in-object@npm:^7.14.5": - version: 7.14.5 - resolution: "@babel/plugin-syntax-private-property-in-object@npm:7.14.5" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.14.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/b317174783e6e96029b743ccff2a67d63d38756876e7e5d0ba53a322e38d9ca452c13354a57de1ad476b4c066dbae699e0ca157441da611117a47af88985ecda - languageName: node - linkType: hard - -"@babel/plugin-syntax-top-level-await@npm:^7.14.5": - version: 7.14.5 - resolution: "@babel/plugin-syntax-top-level-await@npm:7.14.5" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.14.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/bbd1a56b095be7820029b209677b194db9b1d26691fe999856462e66b25b281f031f3dfd91b1619e9dcf95bebe336211833b854d0fb8780d618e35667c2d0d7e - languageName: node - linkType: hard - -"@babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.27.1 - resolution: "@babel/plugin-syntax-typescript@npm:7.27.1" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.27.1" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/87836f7e32af624c2914c73cd6b9803cf324e07d43f61dbb973c6a86f75df725e12540d91fac7141c14b697aa9268fd064220998daced156e96ac3062d7afb41 - languageName: node - linkType: hard - -"@babel/template@npm:^7.27.1, @babel/template@npm:^7.3.3": - version: 7.27.2 - resolution: "@babel/template@npm:7.27.2" - dependencies: - "@babel/code-frame": "npm:^7.27.1" - "@babel/parser": "npm:^7.27.2" - "@babel/types": "npm:^7.27.1" - checksum: 10/fed15a84beb0b9340e5f81566600dbee5eccd92e4b9cc42a944359b1aa1082373391d9d5fc3656981dff27233ec935d0bc96453cf507f60a4b079463999244d8 - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/traverse@npm:7.27.1" - dependencies: - "@babel/code-frame": "npm:^7.27.1" - "@babel/generator": "npm:^7.27.1" - "@babel/parser": "npm:^7.27.1" - "@babel/template": "npm:^7.27.1" - "@babel/types": "npm:^7.27.1" - debug: "npm:^4.3.1" - globals: "npm:^11.1.0" - checksum: 10/9977271aa451293d3f184521412788d6ddaff9d6a29626d7435b5dacd059feb2d7753bc94f59f4f5b76e65bd2e2cabc8a10d7e1f93709feda28619f2e8cbf4d6 - languageName: node - linkType: hard - -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.27.1, @babel/types@npm:^7.3.3": - version: 7.27.1 - resolution: "@babel/types@npm:7.27.1" - dependencies: - "@babel/helper-string-parser": "npm:^7.27.1" - "@babel/helper-validator-identifier": "npm:^7.27.1" - checksum: 10/81f8ada28c4b29695d7d4c4cbfaa5ec3138ccebbeb26628c7c3cc570fdc84f28967c9e68caf4977d51ff4f4d3159c88857ef278317f84f3515dd65e5b8a74995 - languageName: node - linkType: hard - -"@bcoe/v8-coverage@npm:^0.2.3": - version: 0.2.3 - resolution: "@bcoe/v8-coverage@npm:0.2.3" - checksum: 10/1a1f0e356a3bb30b5f1ced6f79c413e6ebacf130421f15fac5fcd8be5ddf98aedb4404d7f5624e3285b700e041f9ef938321f3ca4d359d5b716f96afa120d88d - languageName: node - linkType: hard - "@biomejs/biome@npm:1.9.4": version: 1.9.4 resolution: "@biomejs/biome@npm:1.9.4" @@ -682,282 +303,14 @@ __metadata: languageName: node linkType: hard -"@istanbuljs/load-nyc-config@npm:^1.0.0": - version: 1.1.0 - resolution: "@istanbuljs/load-nyc-config@npm:1.1.0" - dependencies: - camelcase: "npm:^5.3.1" - find-up: "npm:^4.1.0" - get-package-type: "npm:^0.1.0" - js-yaml: "npm:^3.13.1" - resolve-from: "npm:^5.0.0" - checksum: 10/b000a5acd8d4fe6e34e25c399c8bdbb5d3a202b4e10416e17bfc25e12bab90bb56d33db6089ae30569b52686f4b35ff28ef26e88e21e69821d2b85884bd055b8 - languageName: node - linkType: hard - -"@istanbuljs/schema@npm:^0.1.2, @istanbuljs/schema@npm:^0.1.3": - version: 0.1.3 - resolution: "@istanbuljs/schema@npm:0.1.3" - checksum: 10/a9b1e49acdf5efc2f5b2359f2df7f90c5c725f2656f16099e8b2cd3a000619ecca9fc48cf693ba789cf0fd989f6e0df6a22bc05574be4223ecdbb7997d04384b - languageName: node - linkType: hard - -"@jest/console@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/console@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - chalk: "npm:^4.0.0" - jest-message-util: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - slash: "npm:^3.0.0" - checksum: 10/4a80c750e8a31f344233cb9951dee9b77bf6b89377cb131f8b3cde07ff218f504370133a5963f6a786af4d2ce7f85642db206ff7a15f99fe58df4c38ac04899e - languageName: node - linkType: hard - -"@jest/core@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/core@npm:29.7.0" - dependencies: - "@jest/console": "npm:^29.7.0" - "@jest/reporters": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - ansi-escapes: "npm:^4.2.1" - chalk: "npm:^4.0.0" - ci-info: "npm:^3.2.0" - exit: "npm:^0.1.2" - graceful-fs: "npm:^4.2.9" - jest-changed-files: "npm:^29.7.0" - jest-config: "npm:^29.7.0" - jest-haste-map: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-regex-util: "npm:^29.6.3" - jest-resolve: "npm:^29.7.0" - jest-resolve-dependencies: "npm:^29.7.0" - jest-runner: "npm:^29.7.0" - jest-runtime: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - jest-watcher: "npm:^29.7.0" - micromatch: "npm:^4.0.4" - pretty-format: "npm:^29.7.0" - slash: "npm:^3.0.0" - strip-ansi: "npm:^6.0.0" - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - checksum: 10/ab6ac2e562d083faac7d8152ec1cc4eccc80f62e9579b69ed40aedf7211a6b2d57024a6cd53c4e35fd051c39a236e86257d1d99ebdb122291969a0a04563b51e - languageName: node - linkType: hard - -"@jest/environment@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/environment@npm:29.7.0" - dependencies: - "@jest/fake-timers": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - jest-mock: "npm:^29.7.0" - checksum: 10/90b5844a9a9d8097f2cf107b1b5e57007c552f64315da8c1f51217eeb0a9664889d3f145cdf8acf23a84f4d8309a6675e27d5b059659a004db0ea9546d1c81a8 - languageName: node - linkType: hard - -"@jest/expect-utils@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/expect-utils@npm:29.7.0" - dependencies: - jest-get-type: "npm:^29.6.3" - checksum: 10/ef8d379778ef574a17bde2801a6f4469f8022a46a5f9e385191dc73bb1fc318996beaed4513fbd7055c2847227a1bed2469977821866534593a6e52a281499ee - languageName: node - linkType: hard - -"@jest/expect@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/expect@npm:29.7.0" - dependencies: - expect: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - checksum: 10/fea6c3317a8da5c840429d90bfe49d928e89c9e89fceee2149b93a11b7e9c73d2f6e4d7cdf647163da938fc4e2169e4490be6bae64952902bc7a701033fd4880 - languageName: node - linkType: hard - -"@jest/fake-timers@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/fake-timers@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - "@sinonjs/fake-timers": "npm:^10.0.2" - "@types/node": "npm:*" - jest-message-util: "npm:^29.7.0" - jest-mock: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - checksum: 10/9b394e04ffc46f91725ecfdff34c4e043eb7a16e1d78964094c9db3fde0b1c8803e45943a980e8c740d0a3d45661906de1416ca5891a538b0660481a3a828c27 - languageName: node - linkType: hard - -"@jest/globals@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/globals@npm:29.7.0" - dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/expect": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - jest-mock: "npm:^29.7.0" - checksum: 10/97dbb9459135693ad3a422e65ca1c250f03d82b2a77f6207e7fa0edd2c9d2015fbe4346f3dc9ebff1678b9d8da74754d4d440b7837497f8927059c0642a22123 - languageName: node - linkType: hard - -"@jest/reporters@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/reporters@npm:29.7.0" - dependencies: - "@bcoe/v8-coverage": "npm:^0.2.3" - "@jest/console": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@jridgewell/trace-mapping": "npm:^0.3.18" - "@types/node": "npm:*" - chalk: "npm:^4.0.0" - collect-v8-coverage: "npm:^1.0.0" - exit: "npm:^0.1.2" - glob: "npm:^7.1.3" - graceful-fs: "npm:^4.2.9" - istanbul-lib-coverage: "npm:^3.0.0" - istanbul-lib-instrument: "npm:^6.0.0" - istanbul-lib-report: "npm:^3.0.0" - istanbul-lib-source-maps: "npm:^4.0.0" - istanbul-reports: "npm:^3.1.3" - jest-message-util: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-worker: "npm:^29.7.0" - slash: "npm:^3.0.0" - string-length: "npm:^4.0.1" - strip-ansi: "npm:^6.0.0" - v8-to-istanbul: "npm:^9.0.1" - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - checksum: 10/a17d1644b26dea14445cedd45567f4ba7834f980be2ef74447204e14238f121b50d8b858fde648083d2cd8f305f81ba434ba49e37a5f4237a6f2a61180cc73dc - languageName: node - linkType: hard - -"@jest/schemas@npm:^29.6.3": - version: 29.6.3 - resolution: "@jest/schemas@npm:29.6.3" - dependencies: - "@sinclair/typebox": "npm:^0.27.8" - checksum: 10/910040425f0fc93cd13e68c750b7885590b8839066dfa0cd78e7def07bbb708ad869381f725945d66f2284de5663bbecf63e8fdd856e2ae6e261ba30b1687e93 - languageName: node - linkType: hard - -"@jest/source-map@npm:^29.6.3": - version: 29.6.3 - resolution: "@jest/source-map@npm:29.6.3" - dependencies: - "@jridgewell/trace-mapping": "npm:^0.3.18" - callsites: "npm:^3.0.0" - graceful-fs: "npm:^4.2.9" - checksum: 10/bcc5a8697d471396c0003b0bfa09722c3cd879ad697eb9c431e6164e2ea7008238a01a07193dfe3cbb48b1d258eb7251f6efcea36f64e1ebc464ea3c03ae2deb - languageName: node - linkType: hard - -"@jest/test-result@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/test-result@npm:29.7.0" - dependencies: - "@jest/console": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/istanbul-lib-coverage": "npm:^2.0.0" - collect-v8-coverage: "npm:^1.0.0" - checksum: 10/c073ab7dfe3c562bff2b8fee6cc724ccc20aa96bcd8ab48ccb2aa309b4c0c1923a9e703cea386bd6ae9b71133e92810475bb9c7c22328fc63f797ad3324ed189 - languageName: node - linkType: hard - -"@jest/test-sequencer@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/test-sequencer@npm:29.7.0" - dependencies: - "@jest/test-result": "npm:^29.7.0" - graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.7.0" - slash: "npm:^3.0.0" - checksum: 10/4420c26a0baa7035c5419b0892ff8ffe9a41b1583ec54a10db3037cd46a7e29dd3d7202f8aa9d376e9e53be5f8b1bc0d16e1de6880a6d319b033b01dc4c8f639 - languageName: node - linkType: hard - -"@jest/transform@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/transform@npm:29.7.0" - dependencies: - "@babel/core": "npm:^7.11.6" - "@jest/types": "npm:^29.6.3" - "@jridgewell/trace-mapping": "npm:^0.3.18" - babel-plugin-istanbul: "npm:^6.1.1" - chalk: "npm:^4.0.0" - convert-source-map: "npm:^2.0.0" - fast-json-stable-stringify: "npm:^2.1.0" - graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.7.0" - jest-regex-util: "npm:^29.6.3" - jest-util: "npm:^29.7.0" - micromatch: "npm:^4.0.4" - pirates: "npm:^4.0.4" - slash: "npm:^3.0.0" - write-file-atomic: "npm:^4.0.2" - checksum: 10/30f42293545ab037d5799c81d3e12515790bb58513d37f788ce32d53326d0d72ebf5b40f989e6896739aa50a5f77be44686e510966370d58511d5ad2637c68c1 - languageName: node - linkType: hard - -"@jest/types@npm:^29.6.3": - version: 29.6.3 - resolution: "@jest/types@npm:29.6.3" - dependencies: - "@jest/schemas": "npm:^29.6.3" - "@types/istanbul-lib-coverage": "npm:^2.0.0" - "@types/istanbul-reports": "npm:^3.0.0" - "@types/node": "npm:*" - "@types/yargs": "npm:^17.0.8" - chalk: "npm:^4.0.0" - checksum: 10/f74bf512fd09bbe2433a2ad460b04668b7075235eea9a0c77d6a42222c10a79b9747dc2b2a623f140ed40d6865a2ed8f538f3cbb75169120ea863f29a7ed76cd - languageName: node - linkType: hard - -"@jridgewell/gen-mapping@npm:^0.3.5": - version: 0.3.8 - resolution: "@jridgewell/gen-mapping@npm:0.3.8" - dependencies: - "@jridgewell/set-array": "npm:^1.2.1" - "@jridgewell/sourcemap-codec": "npm:^1.4.10" - "@jridgewell/trace-mapping": "npm:^0.3.24" - checksum: 10/9d3a56ab3612ab9b85d38b2a93b87f3324f11c5130859957f6500e4ac8ce35f299d5ccc3ecd1ae87597601ecf83cee29e9afd04c18777c24011073992ff946df - languageName: node - linkType: hard - -"@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": +"@jridgewell/resolve-uri@npm:^3.0.3": version: 3.1.2 resolution: "@jridgewell/resolve-uri@npm:3.1.2" checksum: 10/97106439d750a409c22c8bff822d648f6a71f3aa9bc8e5129efdc36343cd3096ddc4eeb1c62d2fe48e9bdd4db37b05d4646a17114ecebd3bbcacfa2de51c3c1d languageName: node linkType: hard -"@jridgewell/set-array@npm:^1.2.1": - version: 1.2.1 - resolution: "@jridgewell/set-array@npm:1.2.1" - checksum: 10/832e513a85a588f8ed4f27d1279420d8547743cc37fcad5a5a76fc74bb895b013dfe614d0eed9cb860048e6546b798f8f2652020b4b2ba0561b05caa8c654b10 - languageName: node - linkType: hard - -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.5.0": version: 1.5.0 resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" checksum: 10/4ed6123217569a1484419ac53f6ea0d9f3b57e5b57ab30d7c267bdb27792a27eb0e4b08e84a2680aa55cc2f2b411ffd6ec3db01c44fdc6dc43aca4b55f8374fd @@ -974,16 +327,6 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": - version: 0.3.25 - resolution: "@jridgewell/trace-mapping@npm:0.3.25" - dependencies: - "@jridgewell/resolve-uri": "npm:^3.1.0" - "@jridgewell/sourcemap-codec": "npm:^1.4.14" - checksum: 10/dced32160a44b49d531b80a4a2159dceab6b3ddf0c8e95a0deae4b0e894b172defa63d5ac52a19c2068e1fe7d31ea4ba931fbeec103233ecb4208953967120fc - languageName: node - linkType: hard - "@midnight-ntwrk/compact-runtime@npm:^0.8.1": version: 0.8.1 resolution: "@midnight-ntwrk/compact-runtime@npm:0.8.1" @@ -1080,19 +423,6 @@ __metadata: languageName: unknown linkType: soft -"@openzeppelin-midnight/erc721@workspace:contracts/erc721": - version: 0.0.0-use.local - resolution: "@openzeppelin-midnight/erc721@workspace:contracts/erc721" - dependencies: - "@biomejs/biome": "npm:1.9.4" - "@openzeppelin-midnight/compact": "workspace:^" - "@types/jest": "npm:^29.5.6" - "@types/node": "npm:^18.18.6" - jest: "npm:^29.7.0" - typescript: "npm:^5.2.2" - languageName: unknown - linkType: soft - "@openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" @@ -1253,42 +583,17 @@ __metadata: languageName: node linkType: hard -"@sinclair/typebox@npm:^0.27.8": - version: 0.27.8 - resolution: "@sinclair/typebox@npm:0.27.8" - checksum: 10/297f95ff77c82c54de8c9907f186076e715ff2621c5222ba50b8d40a170661c0c5242c763cba2a4791f0f91cb1d8ffa53ea1d7294570cf8cd4694c0e383e484d +"@tsconfig/node10@npm:^1.0.7": + version: 1.0.11 + resolution: "@tsconfig/node10@npm:1.0.11" + checksum: 10/51fe47d55fe1b80ec35e6e5ed30a13665fd3a531945350aa74a14a1e82875fb60b350c2f2a5e72a64831b1b6bc02acb6760c30b3738b54954ec2dea82db7a267 languageName: node linkType: hard -"@sinonjs/commons@npm:^3.0.0": - version: 3.0.1 - resolution: "@sinonjs/commons@npm:3.0.1" - dependencies: - type-detect: "npm:4.0.8" - checksum: 10/a0af217ba7044426c78df52c23cedede6daf377586f3ac58857c565769358ab1f44ebf95ba04bbe38814fba6e316ca6f02870a009328294fc2c555d0f85a7117 - languageName: node - linkType: hard - -"@sinonjs/fake-timers@npm:^10.0.2": - version: 10.3.0 - resolution: "@sinonjs/fake-timers@npm:10.3.0" - dependencies: - "@sinonjs/commons": "npm:^3.0.0" - checksum: 10/78155c7bd866a85df85e22028e046b8d46cf3e840f72260954f5e3ed5bd97d66c595524305a6841ffb3f681a08f6e5cef572a2cce5442a8a232dc29fb409b83e - languageName: node - linkType: hard - -"@tsconfig/node10@npm:^1.0.7": - version: 1.0.11 - resolution: "@tsconfig/node10@npm:1.0.11" - checksum: 10/51fe47d55fe1b80ec35e6e5ed30a13665fd3a531945350aa74a14a1e82875fb60b350c2f2a5e72a64831b1b6bc02acb6760c30b3738b54954ec2dea82db7a267 - languageName: node - linkType: hard - -"@tsconfig/node12@npm:^1.0.7": - version: 1.0.11 - resolution: "@tsconfig/node12@npm:1.0.11" - checksum: 10/5ce29a41b13e7897a58b8e2df11269c5395999e588b9a467386f99d1d26f6c77d1af2719e407621412520ea30517d718d5192a32403b8dfcc163bf33e40a338a +"@tsconfig/node12@npm:^1.0.7": + version: 1.0.11 + resolution: "@tsconfig/node12@npm:1.0.11" + checksum: 10/5ce29a41b13e7897a58b8e2df11269c5395999e588b9a467386f99d1d26f6c77d1af2719e407621412520ea30517d718d5192a32403b8dfcc163bf33e40a338a languageName: node linkType: hard @@ -1306,47 +611,6 @@ __metadata: languageName: node linkType: hard -"@types/babel__core@npm:^7.1.14": - version: 7.20.5 - resolution: "@types/babel__core@npm:7.20.5" - dependencies: - "@babel/parser": "npm:^7.20.7" - "@babel/types": "npm:^7.20.7" - "@types/babel__generator": "npm:*" - "@types/babel__template": "npm:*" - "@types/babel__traverse": "npm:*" - checksum: 10/c32838d280b5ab59d62557f9e331d3831f8e547ee10b4f85cb78753d97d521270cebfc73ce501e9fb27fe71884d1ba75e18658692c2f4117543f0fc4e3e118b3 - languageName: node - linkType: hard - -"@types/babel__generator@npm:*": - version: 7.27.0 - resolution: "@types/babel__generator@npm:7.27.0" - dependencies: - "@babel/types": "npm:^7.0.0" - checksum: 10/f572e67a9a39397664350a4437d8a7fbd34acc83ff4887a8cf08349e39f8aeb5ad2f70fb78a0a0a23a280affe3a5f4c25f50966abdce292bcf31237af1c27b1a - languageName: node - linkType: hard - -"@types/babel__template@npm:*": - version: 7.4.4 - resolution: "@types/babel__template@npm:7.4.4" - dependencies: - "@babel/parser": "npm:^7.1.0" - "@babel/types": "npm:^7.0.0" - checksum: 10/d7a02d2a9b67e822694d8e6a7ddb8f2b71a1d6962dfd266554d2513eefbb205b33ca71a0d163b1caea3981ccf849211f9964d8bd0727124d18ace45aa6c9ae29 - languageName: node - linkType: hard - -"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6": - version: 7.20.7 - resolution: "@types/babel__traverse@npm:7.20.7" - dependencies: - "@babel/types": "npm:^7.20.7" - checksum: 10/d005b58e1c26bdafc1ce564f60db0ee938393c7fc586b1197bdb71a02f7f33f72bc10ae4165776b6cafc77c4b6f2e1a164dd20bc36518c471b1131b153b4baa6 - languageName: node - linkType: hard - "@types/estree@npm:1.0.7, @types/estree@npm:^1.0.0": version: 1.0.7 resolution: "@types/estree@npm:1.0.7" @@ -1354,59 +618,6 @@ __metadata: languageName: node linkType: hard -"@types/graceful-fs@npm:^4.1.3": - version: 4.1.9 - resolution: "@types/graceful-fs@npm:4.1.9" - dependencies: - "@types/node": "npm:*" - checksum: 10/79d746a8f053954bba36bd3d94a90c78de995d126289d656fb3271dd9f1229d33f678da04d10bce6be440494a5a73438e2e363e92802d16b8315b051036c5256 - languageName: node - linkType: hard - -"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": - version: 2.0.6 - resolution: "@types/istanbul-lib-coverage@npm:2.0.6" - checksum: 10/3feac423fd3e5449485afac999dcfcb3d44a37c830af898b689fadc65d26526460bedb889db278e0d4d815a670331796494d073a10ee6e3a6526301fe7415778 - languageName: node - linkType: hard - -"@types/istanbul-lib-report@npm:*": - version: 3.0.3 - resolution: "@types/istanbul-lib-report@npm:3.0.3" - dependencies: - "@types/istanbul-lib-coverage": "npm:*" - checksum: 10/b91e9b60f865ff08cb35667a427b70f6c2c63e88105eadd29a112582942af47ed99c60610180aa8dcc22382fa405033f141c119c69b95db78c4c709fbadfeeb4 - languageName: node - linkType: hard - -"@types/istanbul-reports@npm:^3.0.0": - version: 3.0.4 - resolution: "@types/istanbul-reports@npm:3.0.4" - dependencies: - "@types/istanbul-lib-report": "npm:*" - checksum: 10/93eb18835770b3431f68ae9ac1ca91741ab85f7606f310a34b3586b5a34450ec038c3eed7ab19266635499594de52ff73723a54a72a75b9f7d6a956f01edee95 - languageName: node - linkType: hard - -"@types/jest@npm:^29.5.6": - version: 29.5.14 - resolution: "@types/jest@npm:29.5.14" - dependencies: - expect: "npm:^29.0.0" - pretty-format: "npm:^29.0.0" - checksum: 10/59ec7a9c4688aae8ee529316c43853468b6034f453d08a2e1064b281af9c81234cec986be796288f1bbb29efe943bc950e70c8fa8faae1e460d50e3cf9760f9b - languageName: node - linkType: hard - -"@types/node@npm:*": - version: 22.15.19 - resolution: "@types/node@npm:22.15.19" - dependencies: - undici-types: "npm:~6.21.0" - checksum: 10/02311c2b5dbf2e9e2c17497dc27858bcefbe12a81af0d9b81f865613d8d014726e0eb6cbebfbdb84a327c1b9f9da1347a65a7699ac58c8854fb4daf447031149 - languageName: node - linkType: hard - "@types/node@npm:^18.18.6": version: 18.19.87 resolution: "@types/node@npm:18.19.87" @@ -1416,15 +627,6 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^22": - version: 22.15.19 - resolution: "@types/node@npm:22.15.19" - dependencies: - undici-types: "npm:~6.21.0" - checksum: 10/02311c2b5dbf2e9e2c17497dc27858bcefbe12a81af0d9b81f865613d8d014726e0eb6cbebfbdb84a327c1b9f9da1347a65a7699ac58c8854fb4daf447031149 - languageName: node - linkType: hard - "@types/node@npm:^22.13.10": version: 22.15.2 resolution: "@types/node@npm:22.15.2" @@ -1441,29 +643,6 @@ __metadata: languageName: node linkType: hard -"@types/stack-utils@npm:^2.0.0": - version: 2.0.3 - resolution: "@types/stack-utils@npm:2.0.3" - checksum: 10/72576cc1522090fe497337c2b99d9838e320659ac57fa5560fcbdcbafcf5d0216c6b3a0a8a4ee4fdb3b1f5e3420aa4f6223ab57b82fef3578bec3206425c6cf5 - languageName: node - linkType: hard - -"@types/yargs-parser@npm:*": - version: 21.0.3 - resolution: "@types/yargs-parser@npm:21.0.3" - checksum: 10/a794eb750e8ebc6273a51b12a0002de41343ffe46befef460bdbb57262d187fdf608bc6615b7b11c462c63c3ceb70abe2564c8dd8ee0f7628f38a314f74a9b9b - languageName: node - linkType: hard - -"@types/yargs@npm:^17.0.8": - version: 17.0.33 - resolution: "@types/yargs@npm:17.0.33" - dependencies: - "@types/yargs-parser": "npm:*" - checksum: 10/16f6681bf4d99fb671bf56029141ed01db2862e3db9df7fc92d8bea494359ac96a1b4b1c35a836d1e95e665fb18ad753ab2015fc0db663454e8fd4e5d5e2ef91 - languageName: node - linkType: hard - "@vitest/expect@npm:3.1.3": version: 3.1.3 resolution: "@vitest/expect@npm:3.1.3" @@ -1577,15 +756,6 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^4.2.1": - version: 4.3.2 - resolution: "ansi-escapes@npm:4.3.2" - dependencies: - type-fest: "npm:^0.21.3" - checksum: 10/8661034456193ffeda0c15c8c564a9636b0c04094b7f78bd01517929c17c504090a60f7a75f949f5af91289c264d3e1001d91492c1bd58efc8e100500ce04de2 - languageName: node - linkType: hard - "ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" @@ -1600,7 +770,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": +"ansi-styles@npm:^4.0.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: @@ -1609,13 +779,6 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^5.0.0": - version: 5.2.0 - resolution: "ansi-styles@npm:5.2.0" - checksum: 10/d7f4e97ce0623aea6bc0d90dcd28881ee04cba06c570b97fd3391bd7a268eedfd9d5e2dd4fdcbdd82b8105df5faf6f24aaedc08eaf3da898e702db5948f63469 - languageName: node - linkType: hard - "ansi-styles@npm:^6.1.0": version: 6.2.1 resolution: "ansi-styles@npm:6.2.1" @@ -1623,16 +786,6 @@ __metadata: languageName: node linkType: hard -"anymatch@npm:^3.0.3": - version: 3.1.3 - resolution: "anymatch@npm:3.1.3" - dependencies: - normalize-path: "npm:^3.0.0" - picomatch: "npm:^2.0.4" - checksum: 10/3e044fd6d1d26545f235a9fe4d7a534e2029d8e59fa7fd9f2a6eb21230f6b5380ea1eaf55136e60cbf8e613544b3b766e7a6fa2102e2a3a117505466e3025dc2 - languageName: node - linkType: hard - "arg@npm:^4.1.0": version: 4.1.3 resolution: "arg@npm:4.1.3" @@ -1640,15 +793,6 @@ __metadata: languageName: node linkType: hard -"argparse@npm:^1.0.7": - version: 1.0.10 - resolution: "argparse@npm:1.0.10" - dependencies: - sprintf-js: "npm:~1.0.2" - checksum: 10/c6a621343a553ff3779390bb5ee9c2263d6643ebcd7843227bdde6cc7adbed796eb5540ca98db19e3fd7b4714e1faa51551f8849b268bb62df27ddb15cbcd91e - languageName: node - linkType: hard - "assertion-error@npm:^2.0.1": version: 2.0.1 resolution: "assertion-error@npm:2.0.1" @@ -1656,85 +800,6 @@ __metadata: languageName: node linkType: hard -"babel-jest@npm:^29.7.0": - version: 29.7.0 - resolution: "babel-jest@npm:29.7.0" - dependencies: - "@jest/transform": "npm:^29.7.0" - "@types/babel__core": "npm:^7.1.14" - babel-plugin-istanbul: "npm:^6.1.1" - babel-preset-jest: "npm:^29.6.3" - chalk: "npm:^4.0.0" - graceful-fs: "npm:^4.2.9" - slash: "npm:^3.0.0" - peerDependencies: - "@babel/core": ^7.8.0 - checksum: 10/8a0953bd813b3a8926008f7351611055548869e9a53dd36d6e7e96679001f71e65fd7dbfe253265c3ba6a4e630dc7c845cf3e78b17d758ef1880313ce8fba258 - languageName: node - linkType: hard - -"babel-plugin-istanbul@npm:^6.1.1": - version: 6.1.1 - resolution: "babel-plugin-istanbul@npm:6.1.1" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.0.0" - "@istanbuljs/load-nyc-config": "npm:^1.0.0" - "@istanbuljs/schema": "npm:^0.1.2" - istanbul-lib-instrument: "npm:^5.0.4" - test-exclude: "npm:^6.0.0" - checksum: 10/ffd436bb2a77bbe1942a33245d770506ab2262d9c1b3c1f1da7f0592f78ee7445a95bc2efafe619dd9c1b6ee52c10033d6c7d29ddefe6f5383568e60f31dfe8d - languageName: node - linkType: hard - -"babel-plugin-jest-hoist@npm:^29.6.3": - version: 29.6.3 - resolution: "babel-plugin-jest-hoist@npm:29.6.3" - dependencies: - "@babel/template": "npm:^7.3.3" - "@babel/types": "npm:^7.3.3" - "@types/babel__core": "npm:^7.1.14" - "@types/babel__traverse": "npm:^7.0.6" - checksum: 10/9bfa86ec4170bd805ab8ca5001ae50d8afcb30554d236ba4a7ffc156c1a92452e220e4acbd98daefc12bf0216fccd092d0a2efed49e7e384ec59e0597a926d65 - languageName: node - linkType: hard - -"babel-preset-current-node-syntax@npm:^1.0.0": - version: 1.1.0 - resolution: "babel-preset-current-node-syntax@npm:1.1.0" - dependencies: - "@babel/plugin-syntax-async-generators": "npm:^7.8.4" - "@babel/plugin-syntax-bigint": "npm:^7.8.3" - "@babel/plugin-syntax-class-properties": "npm:^7.12.13" - "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" - "@babel/plugin-syntax-import-attributes": "npm:^7.24.7" - "@babel/plugin-syntax-import-meta": "npm:^7.10.4" - "@babel/plugin-syntax-json-strings": "npm:^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" - "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" - "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" - "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" - "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" - "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" - "@babel/plugin-syntax-top-level-await": "npm:^7.14.5" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/46331111ae72b7121172fd9e6a4a7830f651ad44bf26dbbf77b3c8a60a18009411a3eacb5e72274004290c110371230272109957d5224d155436b4794ead2f1b - languageName: node - linkType: hard - -"babel-preset-jest@npm:^29.6.3": - version: 29.6.3 - resolution: "babel-preset-jest@npm:29.6.3" - dependencies: - babel-plugin-jest-hoist: "npm:^29.6.3" - babel-preset-current-node-syntax: "npm:^1.0.0" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/aa4ff2a8a728d9d698ed521e3461a109a1e66202b13d3494e41eea30729a5e7cc03b3a2d56c594423a135429c37bf63a9fa8b0b9ce275298be3095a88c69f6fb - languageName: node - linkType: hard - "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -1742,16 +807,6 @@ __metadata: languageName: node linkType: hard -"brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" - dependencies: - balanced-match: "npm:^1.0.0" - concat-map: "npm:0.0.1" - checksum: 10/faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 - languageName: node - linkType: hard - "brace-expansion@npm:^2.0.1": version: 2.0.1 resolution: "brace-expansion@npm:2.0.1" @@ -1761,45 +816,6 @@ __metadata: languageName: node linkType: hard -"braces@npm:^3.0.3": - version: 3.0.3 - resolution: "braces@npm:3.0.3" - dependencies: - fill-range: "npm:^7.1.1" - checksum: 10/fad11a0d4697a27162840b02b1fad249c1683cbc510cd5bf1a471f2f8085c046d41094308c577a50a03a579dd99d5a6b3724c4b5e8b14df2c4443844cfcda2c6 - languageName: node - linkType: hard - -"browserslist@npm:^4.24.0": - version: 4.24.5 - resolution: "browserslist@npm:4.24.5" - dependencies: - caniuse-lite: "npm:^1.0.30001716" - electron-to-chromium: "npm:^1.5.149" - node-releases: "npm:^2.0.19" - update-browserslist-db: "npm:^1.1.3" - bin: - browserslist: cli.js - checksum: 10/93fde829b77f20e2c4e1e0eaed154681c05e4828420e4afba790d480daa5de742977a44bbac8567881b8fbec3da3dea7ca1cb578ac1fd4385ef4ae91ca691d64 - languageName: node - linkType: hard - -"bser@npm:2.1.1": - version: 2.1.1 - resolution: "bser@npm:2.1.1" - dependencies: - node-int64: "npm:^0.4.0" - checksum: 10/edba1b65bae682450be4117b695997972bd9a3c4dfee029cab5bcb72ae5393a79a8f909b8bc77957eb0deec1c7168670f18f4d5c556f46cdd3bca5f3b3a8d020 - languageName: node - linkType: hard - -"buffer-from@npm:^1.0.0": - version: 1.1.2 - resolution: "buffer-from@npm:1.1.2" - checksum: 10/0448524a562b37d4d7ed9efd91685a5b77a50672c556ea254ac9a6d30e3403a517d8981f10e565db24e8339413b43c97ca2951f10e399c6125a0d8911f5679bb - languageName: node - linkType: hard - "cac@npm:^6.7.14": version: 6.7.14 resolution: "cac@npm:6.7.14" @@ -1827,34 +843,6 @@ __metadata: languageName: node linkType: hard -"callsites@npm:^3.0.0": - version: 3.1.0 - resolution: "callsites@npm:3.1.0" - checksum: 10/072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 - languageName: node - linkType: hard - -"camelcase@npm:^5.3.1": - version: 5.3.1 - resolution: "camelcase@npm:5.3.1" - checksum: 10/e6effce26b9404e3c0f301498184f243811c30dfe6d0b9051863bd8e4034d09c8c2923794f280d6827e5aa055f6c434115ff97864a16a963366fb35fd673024b - languageName: node - linkType: hard - -"camelcase@npm:^6.2.0": - version: 6.3.0 - resolution: "camelcase@npm:6.3.0" - checksum: 10/8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001716": - version: 1.0.30001718 - resolution: "caniuse-lite@npm:1.0.30001718" - checksum: 10/e172a4c156f743cc947e659f353ad9edb045725cc109a02cc792dcbf98569356ebfa4bb4356e3febf87427aab0951c34c1ee5630629334f25ae6f76de7d86fd0 - languageName: node - linkType: hard - "chai@npm:^5.2.0": version: 5.2.0 resolution: "chai@npm:5.2.0" @@ -1868,16 +856,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^4.0.0": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" - dependencies: - ansi-styles: "npm:^4.1.0" - supports-color: "npm:^7.1.0" - checksum: 10/cb3f3e594913d63b1814d7ca7c9bafbf895f75fbf93b92991980610dfd7b48500af4e3a5d4e3a8f337990a96b168d7eb84ee55efdce965e2ee8efc20f8c8f139 - languageName: node - linkType: hard - "chalk@npm:^5.3.0, chalk@npm:^5.4.1": version: 5.4.1 resolution: "chalk@npm:5.4.1" @@ -1885,13 +863,6 @@ __metadata: languageName: node linkType: hard -"char-regex@npm:^1.0.2": - version: 1.0.2 - resolution: "char-regex@npm:1.0.2" - checksum: 10/1ec5c2906adb9f84e7f6732a40baef05d7c85401b82ffcbc44b85fbd0f7a2b0c2a96f2eb9cf55cae3235dc12d4023003b88f09bcae8be9ae894f52ed746f4d48 - languageName: node - linkType: hard - "check-error@npm:^2.1.1": version: 2.1.1 resolution: "check-error@npm:2.1.1" @@ -1906,20 +877,6 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^3.2.0": - version: 3.9.0 - resolution: "ci-info@npm:3.9.0" - checksum: 10/75bc67902b4d1c7b435497adeb91598f6d52a3389398e44294f6601b20cfef32cf2176f7be0eb961d9e085bb333a8a5cae121cb22f81cf238ae7f58eb80e9397 - languageName: node - linkType: hard - -"cjs-module-lexer@npm:^1.0.0": - version: 1.4.3 - resolution: "cjs-module-lexer@npm:1.4.3" - checksum: 10/d2b92f919a2dedbfd61d016964fce8da0035f827182ed6839c97cac56e8a8077cfa6a59388adfe2bc588a19cef9bbe830d683a76a6e93c51f65852062cfe2591 - languageName: node - linkType: hard - "cli-cursor@npm:^5.0.0": version: 5.0.0 resolution: "cli-cursor@npm:5.0.0" @@ -1936,31 +893,6 @@ __metadata: languageName: node linkType: hard -"cliui@npm:^8.0.1": - version: 8.0.1 - resolution: "cliui@npm:8.0.1" - dependencies: - string-width: "npm:^4.2.0" - strip-ansi: "npm:^6.0.1" - wrap-ansi: "npm:^7.0.0" - checksum: 10/eaa5561aeb3135c2cddf7a3b3f562fc4238ff3b3fc666869ef2adf264be0f372136702f16add9299087fb1907c2e4ec5dbfe83bd24bce815c70a80c6c1a2e950 - languageName: node - linkType: hard - -"co@npm:^4.6.0": - version: 4.6.0 - resolution: "co@npm:4.6.0" - checksum: 10/a5d9f37091c70398a269e625cedff5622f200ed0aa0cff22ee7b55ed74a123834b58711776eb0f1dc58eb6ebbc1185aa7567b57bd5979a948c6e4f85073e2c05 - languageName: node - linkType: hard - -"collect-v8-coverage@npm:^1.0.0": - version: 1.0.2 - resolution: "collect-v8-coverage@npm:1.0.2" - checksum: 10/30ea7d5c9ee51f2fdba4901d4186c5b7114a088ef98fd53eda3979da77eed96758a2cae81cc6d97e239aaea6065868cf908b24980663f7b7e96aa291b3e12fa4 - languageName: node - linkType: hard - "color-convert@npm:^2.0.1": version: 2.0.1 resolution: "color-convert@npm:2.0.1" @@ -1977,37 +909,6 @@ __metadata: languageName: node linkType: hard -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 10/9680699c8e2b3af0ae22592cb764acaf973f292a7b71b8a06720233011853a58e256c89216a10cbe889727532fd77f8bcd49a760cedfde271b8e006c20e079f2 - languageName: node - linkType: hard - -"convert-source-map@npm:^2.0.0": - version: 2.0.0 - resolution: "convert-source-map@npm:2.0.0" - checksum: 10/c987be3ec061348cdb3c2bfb924bec86dea1eacad10550a85ca23edb0fe3556c3a61c7399114f3331ccb3499d7fd0285ab24566e5745929412983494c3926e15 - languageName: node - linkType: hard - -"create-jest@npm:^29.7.0": - version: 29.7.0 - resolution: "create-jest@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - chalk: "npm:^4.0.0" - exit: "npm:^0.1.2" - graceful-fs: "npm:^4.2.9" - jest-config: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - prompts: "npm:^2.0.1" - bin: - create-jest: bin/create-jest.js - checksum: 10/847b4764451672b4174be4d5c6d7d63442ec3aa5f3de52af924e4d996d87d7801c18e125504f25232fc75840f6625b3ac85860fac6ce799b5efae7bdcaf4a2b7 - languageName: node - linkType: hard - "create-require@npm:^1.1.0": version: 1.1.1 resolution: "create-require@npm:1.1.1" @@ -2015,7 +916,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": +"cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -2026,7 +927,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.4, debug@npm:^4.4.0": +"debug@npm:4, debug@npm:^4.3.4, debug@npm:^4.4.0": version: 4.4.1 resolution: "debug@npm:4.4.1" dependencies: @@ -2038,18 +939,6 @@ __metadata: languageName: node linkType: hard -"dedent@npm:^1.0.0": - version: 1.6.0 - resolution: "dedent@npm:1.6.0" - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - checksum: 10/f100cb11001309f2185c4334c6f29e5323c1e73b7b75e3b1893bc71ef53cd13fb80534efc8fa7163a891ede633e310a9c600ba38c363cc9d14a72f238fe47078 - languageName: node - linkType: hard - "deep-eql@npm:^5.0.1": version: 5.0.2 resolution: "deep-eql@npm:5.0.2" @@ -2057,27 +946,6 @@ __metadata: languageName: node linkType: hard -"deepmerge@npm:^4.2.2": - version: 4.3.1 - resolution: "deepmerge@npm:4.3.1" - checksum: 10/058d9e1b0ff1a154468bf3837aea436abcfea1ba1d165ddaaf48ca93765fdd01a30d33c36173da8fbbed951dd0a267602bc782fe288b0fc4b7e1e7091afc4529 - languageName: node - linkType: hard - -"detect-newline@npm:^3.0.0": - version: 3.1.0 - resolution: "detect-newline@npm:3.1.0" - checksum: 10/ae6cd429c41ad01b164c59ea36f264a2c479598e61cba7c99da24175a7ab80ddf066420f2bec9a1c57a6bead411b4655ff15ad7d281c000a89791f48cbe939e7 - languageName: node - linkType: hard - -"diff-sequences@npm:^29.6.3": - version: 29.6.3 - resolution: "diff-sequences@npm:29.6.3" - checksum: 10/179daf9d2f9af5c57ad66d97cb902a538bcf8ed64963fa7aa0c329b3de3665ce2eb6ffdc2f69f29d445fa4af2517e5e55e5b6e00c00a9ae4f43645f97f7078cb - languageName: node - linkType: hard - "diff@npm:^4.0.1": version: 4.0.2 resolution: "diff@npm:4.0.2" @@ -2092,20 +960,6 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.5.149": - version: 1.5.155 - resolution: "electron-to-chromium@npm:1.5.155" - checksum: 10/3c3fff052b8cdf18edca56b45ed1d52f665c943e6ef5c09cb33b2d06b774d705cc7679ea886bdde35b0ebafe30d6f570223fcfc7b687d7c0c34286368d7f4976 - languageName: node - linkType: hard - -"emittery@npm:^0.13.1": - version: 0.13.1 - resolution: "emittery@npm:0.13.1" - checksum: 10/fbe214171d878b924eedf1757badf58a5dce071cd1fa7f620fa841a0901a80d6da47ff05929d53163105e621ce11a71b9d8acb1148ffe1745e045145f6e69521 - languageName: node - linkType: hard - "emoji-regex@npm:^10.3.0": version: 10.4.0 resolution: "emoji-regex@npm:10.4.0" @@ -2150,15 +1004,6 @@ __metadata: languageName: node linkType: hard -"error-ex@npm:^1.3.1": - version: 1.3.2 - resolution: "error-ex@npm:1.3.2" - dependencies: - is-arrayish: "npm:^0.2.1" - checksum: 10/d547740aa29c34e753fb6fed2c5de81802438529c12b3673bd37b6bb1fe49b9b7abdc3c11e6062fe625d8a296b3cf769a80f878865e25e685f787763eede3ffb - languageName: node - linkType: hard - "es-module-lexer@npm:^1.7.0": version: 1.7.0 resolution: "es-module-lexer@npm:1.7.0" @@ -2252,30 +1097,6 @@ __metadata: languageName: node linkType: hard -"escalade@npm:^3.1.1, escalade@npm:^3.2.0": - version: 3.2.0 - resolution: "escalade@npm:3.2.0" - checksum: 10/9d7169e3965b2f9ae46971afa392f6e5a25545ea30f2e2dd99c9b0a95a3f52b5653681a84f5b2911a413ddad2d7a93d3514165072f349b5ffc59c75a899970d6 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^2.0.0": - version: 2.0.0 - resolution: "escape-string-regexp@npm:2.0.0" - checksum: 10/9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 - languageName: node - linkType: hard - -"esprima@npm:^4.0.0": - version: 4.0.1 - resolution: "esprima@npm:4.0.1" - bin: - esparse: ./bin/esparse.js - esvalidate: ./bin/esvalidate.js - checksum: 10/f1d3c622ad992421362294f7acf866aa9409fbad4eb2e8fa230bd33944ce371d32279667b242d8b8907ec2b6ad7353a717f3c0e60e748873a34a7905174bc0eb - languageName: node - linkType: hard - "estree-walker@npm:^3.0.3": version: 3.0.3 resolution: "estree-walker@npm:3.0.3" @@ -2285,30 +1106,6 @@ __metadata: languageName: node linkType: hard -"execa@npm:^5.0.0": - version: 5.1.1 - resolution: "execa@npm:5.1.1" - dependencies: - cross-spawn: "npm:^7.0.3" - get-stream: "npm:^6.0.0" - human-signals: "npm:^2.1.0" - is-stream: "npm:^2.0.0" - merge-stream: "npm:^2.0.0" - npm-run-path: "npm:^4.0.1" - onetime: "npm:^5.1.2" - signal-exit: "npm:^3.0.3" - strip-final-newline: "npm:^2.0.0" - checksum: 10/8ada91f2d70f7dff702c861c2c64f21dfdc1525628f3c0454fd6f02fce65f7b958616cbd2b99ca7fa4d474e461a3d363824e91b3eb881705231abbf387470597 - languageName: node - linkType: hard - -"exit@npm:^0.1.2": - version: 0.1.2 - resolution: "exit@npm:0.1.2" - checksum: 10/387555050c5b3c10e7a9e8df5f43194e95d7737c74532c409910e585d5554eaff34960c166643f5e23d042196529daad059c292dcf1fb61b8ca878d3677f4b87 - languageName: node - linkType: hard - "expect-type@npm:^1.2.1": version: 1.2.1 resolution: "expect-type@npm:1.2.1" @@ -2316,19 +1113,6 @@ __metadata: languageName: node linkType: hard -"expect@npm:^29.0.0, expect@npm:^29.7.0": - version: 29.7.0 - resolution: "expect@npm:29.7.0" - dependencies: - "@jest/expect-utils": "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - jest-matcher-utils: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - checksum: 10/63f97bc51f56a491950fb525f9ad94f1916e8a014947f8d8445d3847a665b5471b768522d659f5e865db20b6c2033d2ac10f35fcbd881a4d26407a4f6f18451a - languageName: node - linkType: hard - "exponential-backoff@npm:^3.1.1": version: 3.1.2 resolution: "exponential-backoff@npm:3.1.2" @@ -2345,22 +1129,6 @@ __metadata: languageName: node linkType: hard -"fast-json-stable-stringify@npm:^2.1.0": - version: 2.1.0 - resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: 10/2c20055c1fa43c922428f16ca8bb29f2807de63e5c851f665f7ac9790176c01c3b40335257736b299764a8d383388dabc73c8083b8e1bc3d99f0a941444ec60e - languageName: node - linkType: hard - -"fb-watchman@npm:^2.0.0": - version: 2.0.2 - resolution: "fb-watchman@npm:2.0.2" - dependencies: - bser: "npm:2.1.1" - checksum: 10/4f95d336fb805786759e383fd7fff342ceb7680f53efcc0ef82f502eb479ce35b98e8b207b6dfdfeea0eba845862107dc73813775fc6b56b3098c6e90a2dad77 - languageName: node - linkType: hard - "fdir@npm:^6.4.4": version: 6.4.4 resolution: "fdir@npm:6.4.4" @@ -2373,25 +1141,6 @@ __metadata: languageName: node linkType: hard -"fill-range@npm:^7.1.1": - version: 7.1.1 - resolution: "fill-range@npm:7.1.1" - dependencies: - to-regex-range: "npm:^5.0.1" - checksum: 10/a7095cb39e5bc32fada2aa7c7249d3f6b01bd1ce461a61b0adabacccabd9198500c6fb1f68a7c851a657e273fce2233ba869638897f3d7ed2e87a2d89b4436ea - languageName: node - linkType: hard - -"find-up@npm:^4.0.0, find-up@npm:^4.1.0": - version: 4.1.0 - resolution: "find-up@npm:4.1.0" - dependencies: - locate-path: "npm:^5.0.0" - path-exists: "npm:^4.0.0" - checksum: 10/4c172680e8f8c1f78839486e14a43ef82e9decd0e74145f40707cc42e7420506d5ec92d9a11c22bd2c48fb0c384ea05dd30e10dd152fefeec6f2f75282a8b844 - languageName: node - linkType: hard - "foreground-child@npm:^3.1.0": version: 3.3.1 resolution: "foreground-child@npm:3.3.1" @@ -2411,14 +1160,7 @@ __metadata: languageName: node linkType: hard -"fs.realpath@npm:^1.0.0": - version: 1.0.0 - resolution: "fs.realpath@npm:1.0.0" - checksum: 10/e703107c28e362d8d7b910bbcbfd371e640a3bb45ae157a362b5952c0030c0b6d4981140ec319b347bce7adc025dd7813da1ff908a945ac214d64f5402a51b96 - languageName: node - linkType: hard - -"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": +"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" dependencies: @@ -2428,7 +1170,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": +"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" dependencies: @@ -2437,27 +1179,6 @@ __metadata: languageName: node linkType: hard -"function-bind@npm:^1.1.2": - version: 1.1.2 - resolution: "function-bind@npm:1.1.2" - checksum: 10/185e20d20f10c8d661d59aac0f3b63b31132d492e1b11fcc2a93cb2c47257ebaee7407c38513efd2b35cafdf972d9beb2ea4593c1e0f3bf8f2744836928d7454 - languageName: node - linkType: hard - -"gensync@npm:^1.0.0-beta.2": - version: 1.0.0-beta.2 - resolution: "gensync@npm:1.0.0-beta.2" - checksum: 10/17d8333460204fbf1f9160d067e1e77f908a5447febb49424b8ab043026049835c9ef3974445c57dbd39161f4d2b04356d7de12b2eecaa27a7a7ea7d871cbedd - languageName: node - linkType: hard - -"get-caller-file@npm:^2.0.5": - version: 2.0.5 - resolution: "get-caller-file@npm:2.0.5" - checksum: 10/b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9 - languageName: node - linkType: hard - "get-east-asian-width@npm:^1.0.0": version: 1.3.0 resolution: "get-east-asian-width@npm:1.3.0" @@ -2465,20 +1186,6 @@ __metadata: languageName: node linkType: hard -"get-package-type@npm:^0.1.0": - version: 0.1.0 - resolution: "get-package-type@npm:0.1.0" - checksum: 10/bba0811116d11e56d702682ddef7c73ba3481f114590e705fc549f4d868972263896af313c57a25c076e3c0d567e11d919a64ba1b30c879be985fc9d44f96148 - languageName: node - linkType: hard - -"get-stream@npm:^6.0.0": - version: 6.0.1 - resolution: "get-stream@npm:6.0.1" - checksum: 10/781266d29725f35c59f1d214aedc92b0ae855800a980800e2923b3fbc4e56b3cb6e462c42e09a1cf1a00c64e056a78fa407cbe06c7c92b7e5cd49b4b85c2a497 - languageName: node - linkType: hard - "glob@npm:^10.2.2": version: 10.4.5 resolution: "glob@npm:10.4.5" @@ -2495,57 +1202,13 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.3, glob@npm:^7.1.4": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^3.1.1" - once: "npm:^1.3.0" - path-is-absolute: "npm:^1.0.0" - checksum: 10/59452a9202c81d4508a43b8af7082ca5c76452b9fcc4a9ab17655822e6ce9b21d4f8fbadabe4fe3faef448294cec249af305e2cd824b7e9aaf689240e5e96a7b - languageName: node - linkType: hard - -"globals@npm:^11.1.0": - version: 11.12.0 - resolution: "globals@npm:11.12.0" - checksum: 10/9f054fa38ff8de8fa356502eb9d2dae0c928217b8b5c8de1f09f5c9b6c8a96d8b9bd3afc49acbcd384a98a81fea713c859e1b09e214c60509517bb8fc2bc13c2 - languageName: node - linkType: hard - -"graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 languageName: node linkType: hard -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 10/261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad - languageName: node - linkType: hard - -"hasown@npm:^2.0.2": - version: 2.0.2 - resolution: "hasown@npm:2.0.2" - dependencies: - function-bind: "npm:^1.1.2" - checksum: 10/7898a9c1788b2862cf0f9c345a6bec77ba4a0c0983c7f19d610c382343d4f98fa260686b225dfb1f88393a66679d2ec58ee310c1d6868c081eda7918f32cc70a - languageName: node - linkType: hard - -"html-escaper@npm:^2.0.0": - version: 2.0.2 - resolution: "html-escaper@npm:2.0.2" - checksum: 10/034d74029dcca544a34fb6135e98d427acd73019796ffc17383eaa3ec2fe1c0471dcbbc8f8ed39e46e86d43ccd753a160631615e4048285e313569609b66d5b7 - languageName: node - linkType: hard - "http-cache-semantics@npm:^4.1.1": version: 4.2.0 resolution: "http-cache-semantics@npm:4.2.0" @@ -2573,13 +1236,6 @@ __metadata: languageName: node linkType: hard -"human-signals@npm:^2.1.0": - version: 2.1.0 - resolution: "human-signals@npm:2.1.0" - checksum: 10/df59be9e0af479036798a881d1f136c4a29e0b518d4abb863afbd11bf30efa3eeb1d0425fc65942dcc05ab3bf40205ea436b0ff389f2cd20b75b8643d539bf86 - languageName: node - linkType: hard - "iconv-lite@npm:^0.6.2": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" @@ -2589,18 +1245,6 @@ __metadata: languageName: node linkType: hard -"import-local@npm:^3.0.2": - version: 3.2.0 - resolution: "import-local@npm:3.2.0" - dependencies: - pkg-dir: "npm:^4.2.0" - resolve-cwd: "npm:^3.0.0" - bin: - import-local-fixture: fixtures/cli.js - checksum: 10/0b0b0b412b2521739fbb85eeed834a3c34de9bc67e670b3d0b86248fc460d990a7b116ad056c084b87a693ef73d1f17268d6a5be626bb43c998a8b1c8a230004 - languageName: node - linkType: hard - "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -2608,23 +1252,6 @@ __metadata: languageName: node linkType: hard -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: "npm:^1.3.0" - wrappy: "npm:1" - checksum: 10/d2ebd65441a38c8336c223d1b80b921b9fa737e37ea466fd7e253cb000c64ae1f17fa59e68130ef5bda92cfd8d36b83d37dab0eb0a4558bcfec8e8cdfd2dcb67 - languageName: node - linkType: hard - -"inherits@npm:2": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 10/cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521 - languageName: node - linkType: hard - "ip-address@npm:^9.0.5": version: 9.0.5 resolution: "ip-address@npm:9.0.5" @@ -2635,22 +1262,6 @@ __metadata: languageName: node linkType: hard -"is-arrayish@npm:^0.2.1": - version: 0.2.1 - resolution: "is-arrayish@npm:0.2.1" - checksum: 10/73ced84fa35e59e2c57da2d01e12cd01479f381d7f122ce41dcbb713f09dbfc651315832cd2bf8accba7681a69e4d6f1e03941d94dd10040d415086360e7005e - languageName: node - linkType: hard - -"is-core-module@npm:^2.16.0": - version: 2.16.1 - resolution: "is-core-module@npm:2.16.1" - dependencies: - hasown: "npm:^2.0.2" - checksum: 10/452b2c2fb7f889cbbf7e54609ef92cf6c24637c568acc7e63d166812a0fb365ae8a504c333a29add8bdb1686704068caa7f4e4b639b650dde4f00a038b8941fb - languageName: node - linkType: hard - "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -2658,13 +1269,6 @@ __metadata: languageName: node linkType: hard -"is-generator-fn@npm:^2.0.0": - version: 2.1.0 - resolution: "is-generator-fn@npm:2.1.0" - checksum: 10/a6ad5492cf9d1746f73b6744e0c43c0020510b59d56ddcb78a91cbc173f09b5e6beff53d75c9c5a29feb618bfef2bf458e025ecf3a57ad2268e2fb2569f56215 - languageName: node - linkType: hard - "is-interactive@npm:^2.0.0": version: 2.0.0 resolution: "is-interactive@npm:2.0.0" @@ -2672,20 +1276,6 @@ __metadata: languageName: node linkType: hard -"is-number@npm:^7.0.0": - version: 7.0.0 - resolution: "is-number@npm:7.0.0" - checksum: 10/6a6c3383f68afa1e05b286af866017c78f1226d43ac8cb064e115ff9ed85eb33f5c4f7216c96a71e4dfea289ef52c5da3aef5bbfade8ffe47a0465d70c0c8e86 - languageName: node - linkType: hard - -"is-stream@npm:^2.0.0": - version: 2.0.1 - resolution: "is-stream@npm:2.0.1" - checksum: 10/b8e05ccdf96ac330ea83c12450304d4a591f9958c11fd17bed240af8d5ffe08aedafa4c0f4cfccd4d28dc9d4d129daca1023633d5c11601a6cbc77521f6fae66 - languageName: node - linkType: hard - "is-unicode-supported@npm:^1.3.0": version: 1.3.0 resolution: "is-unicode-supported@npm:1.3.0" @@ -2714,71 +1304,6 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": - version: 3.2.2 - resolution: "istanbul-lib-coverage@npm:3.2.2" - checksum: 10/40bbdd1e937dfd8c830fa286d0f665e81b7a78bdabcd4565f6d5667c99828bda3db7fb7ac6b96a3e2e8a2461ddbc5452d9f8bc7d00cb00075fa6a3e99f5b6a81 - languageName: node - linkType: hard - -"istanbul-lib-instrument@npm:^5.0.4": - version: 5.2.1 - resolution: "istanbul-lib-instrument@npm:5.2.1" - dependencies: - "@babel/core": "npm:^7.12.3" - "@babel/parser": "npm:^7.14.7" - "@istanbuljs/schema": "npm:^0.1.2" - istanbul-lib-coverage: "npm:^3.2.0" - semver: "npm:^6.3.0" - checksum: 10/bbc4496c2f304d799f8ec22202ab38c010ac265c441947f075c0f7d46bd440b45c00e46017cf9053453d42182d768b1d6ed0e70a142c95ab00df9843aa5ab80e - languageName: node - linkType: hard - -"istanbul-lib-instrument@npm:^6.0.0": - version: 6.0.3 - resolution: "istanbul-lib-instrument@npm:6.0.3" - dependencies: - "@babel/core": "npm:^7.23.9" - "@babel/parser": "npm:^7.23.9" - "@istanbuljs/schema": "npm:^0.1.3" - istanbul-lib-coverage: "npm:^3.2.0" - semver: "npm:^7.5.4" - checksum: 10/aa5271c0008dfa71b6ecc9ba1e801bf77b49dc05524e8c30d58aaf5b9505e0cd12f25f93165464d4266a518c5c75284ecb598fbd89fec081ae77d2c9d3327695 - languageName: node - linkType: hard - -"istanbul-lib-report@npm:^3.0.0": - version: 3.0.1 - resolution: "istanbul-lib-report@npm:3.0.1" - dependencies: - istanbul-lib-coverage: "npm:^3.0.0" - make-dir: "npm:^4.0.0" - supports-color: "npm:^7.1.0" - checksum: 10/86a83421ca1cf2109a9f6d193c06c31ef04a45e72a74579b11060b1e7bb9b6337a4e6f04abfb8857e2d569c271273c65e855ee429376a0d7c91ad91db42accd1 - languageName: node - linkType: hard - -"istanbul-lib-source-maps@npm:^4.0.0": - version: 4.0.1 - resolution: "istanbul-lib-source-maps@npm:4.0.1" - dependencies: - debug: "npm:^4.1.1" - istanbul-lib-coverage: "npm:^3.0.0" - source-map: "npm:^0.6.1" - checksum: 10/5526983462799aced011d776af166e350191b816821ea7bcf71cab3e5272657b062c47dc30697a22a43656e3ced78893a42de677f9ccf276a28c913190953b82 - languageName: node - linkType: hard - -"istanbul-reports@npm:^3.1.3": - version: 3.1.7 - resolution: "istanbul-reports@npm:3.1.7" - dependencies: - html-escaper: "npm:^2.0.0" - istanbul-lib-report: "npm:^3.0.0" - checksum: 10/f1faaa4684efaf57d64087776018d7426312a59aa6eeb4e0e3a777347d23cd286ad18f427e98f0e3dee666103d7404c9d7abc5f240406a912fa16bd6695437fa - languageName: node - linkType: hard - "jackspeak@npm:^3.1.2": version: 3.4.3 resolution: "jackspeak@npm:3.4.3" @@ -2792,464 +1317,6 @@ __metadata: languageName: node linkType: hard -"jest-changed-files@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-changed-files@npm:29.7.0" - dependencies: - execa: "npm:^5.0.0" - jest-util: "npm:^29.7.0" - p-limit: "npm:^3.1.0" - checksum: 10/3d93742e56b1a73a145d55b66e96711fbf87ef89b96c2fab7cfdfba8ec06612591a982111ca2b712bb853dbc16831ec8b43585a2a96b83862d6767de59cbf83d - languageName: node - linkType: hard - -"jest-circus@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-circus@npm:29.7.0" - dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/expect": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - chalk: "npm:^4.0.0" - co: "npm:^4.6.0" - dedent: "npm:^1.0.0" - is-generator-fn: "npm:^2.0.0" - jest-each: "npm:^29.7.0" - jest-matcher-utils: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-runtime: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - p-limit: "npm:^3.1.0" - pretty-format: "npm:^29.7.0" - pure-rand: "npm:^6.0.0" - slash: "npm:^3.0.0" - stack-utils: "npm:^2.0.3" - checksum: 10/716a8e3f40572fd0213bcfc1da90274bf30d856e5133af58089a6ce45089b63f4d679bd44e6be9d320e8390483ebc3ae9921981993986d21639d9019b523123d - languageName: node - linkType: hard - -"jest-cli@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-cli@npm:29.7.0" - dependencies: - "@jest/core": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - chalk: "npm:^4.0.0" - create-jest: "npm:^29.7.0" - exit: "npm:^0.1.2" - import-local: "npm:^3.0.2" - jest-config: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - yargs: "npm:^17.3.1" - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - bin: - jest: bin/jest.js - checksum: 10/6cc62b34d002c034203065a31e5e9a19e7c76d9e8ef447a6f70f759c0714cb212c6245f75e270ba458620f9c7b26063cd8cf6cd1f7e3afd659a7cc08add17307 - languageName: node - linkType: hard - -"jest-config@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-config@npm:29.7.0" - dependencies: - "@babel/core": "npm:^7.11.6" - "@jest/test-sequencer": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - babel-jest: "npm:^29.7.0" - chalk: "npm:^4.0.0" - ci-info: "npm:^3.2.0" - deepmerge: "npm:^4.2.2" - glob: "npm:^7.1.3" - graceful-fs: "npm:^4.2.9" - jest-circus: "npm:^29.7.0" - jest-environment-node: "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - jest-regex-util: "npm:^29.6.3" - jest-resolve: "npm:^29.7.0" - jest-runner: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - micromatch: "npm:^4.0.4" - parse-json: "npm:^5.2.0" - pretty-format: "npm:^29.7.0" - slash: "npm:^3.0.0" - strip-json-comments: "npm:^3.1.1" - peerDependencies: - "@types/node": "*" - ts-node: ">=9.0.0" - peerDependenciesMeta: - "@types/node": - optional: true - ts-node: - optional: true - checksum: 10/6bdf570e9592e7d7dd5124fc0e21f5fe92bd15033513632431b211797e3ab57eaa312f83cc6481b3094b72324e369e876f163579d60016677c117ec4853cf02b - languageName: node - linkType: hard - -"jest-diff@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-diff@npm:29.7.0" - dependencies: - chalk: "npm:^4.0.0" - diff-sequences: "npm:^29.6.3" - jest-get-type: "npm:^29.6.3" - pretty-format: "npm:^29.7.0" - checksum: 10/6f3a7eb9cd9de5ea9e5aa94aed535631fa6f80221832952839b3cb59dd419b91c20b73887deb0b62230d06d02d6b6cf34ebb810b88d904bb4fe1e2e4f0905c98 - languageName: node - linkType: hard - -"jest-docblock@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-docblock@npm:29.7.0" - dependencies: - detect-newline: "npm:^3.0.0" - checksum: 10/8d48818055bc96c9e4ec2e217a5a375623c0d0bfae8d22c26e011074940c202aa2534a3362294c81d981046885c05d304376afba9f2874143025981148f3e96d - languageName: node - linkType: hard - -"jest-each@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-each@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - chalk: "npm:^4.0.0" - jest-get-type: "npm:^29.6.3" - jest-util: "npm:^29.7.0" - pretty-format: "npm:^29.7.0" - checksum: 10/bd1a077654bdaa013b590deb5f7e7ade68f2e3289180a8c8f53bc8a49f3b40740c0ec2d3a3c1aee906f682775be2bebbac37491d80b634d15276b0aa0f2e3fda - languageName: node - linkType: hard - -"jest-environment-node@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-environment-node@npm:29.7.0" - dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/fake-timers": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - jest-mock: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - checksum: 10/9cf7045adf2307cc93aed2f8488942e39388bff47ec1df149a997c6f714bfc66b2056768973770d3f8b1bf47396c19aa564877eb10ec978b952c6018ed1bd637 - languageName: node - linkType: hard - -"jest-get-type@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-get-type@npm:29.6.3" - checksum: 10/88ac9102d4679d768accae29f1e75f592b760b44277df288ad76ce5bf038c3f5ce3719dea8aa0f035dac30e9eb034b848ce716b9183ad7cc222d029f03e92205 - languageName: node - linkType: hard - -"jest-haste-map@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-haste-map@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - "@types/graceful-fs": "npm:^4.1.3" - "@types/node": "npm:*" - anymatch: "npm:^3.0.3" - fb-watchman: "npm:^2.0.0" - fsevents: "npm:^2.3.2" - graceful-fs: "npm:^4.2.9" - jest-regex-util: "npm:^29.6.3" - jest-util: "npm:^29.7.0" - jest-worker: "npm:^29.7.0" - micromatch: "npm:^4.0.4" - walker: "npm:^1.0.8" - dependenciesMeta: - fsevents: - optional: true - checksum: 10/8531b42003581cb18a69a2774e68c456fb5a5c3280b1b9b77475af9e346b6a457250f9d756bfeeae2fe6cbc9ef28434c205edab9390ee970a919baddfa08bb85 - languageName: node - linkType: hard - -"jest-leak-detector@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-leak-detector@npm:29.7.0" - dependencies: - jest-get-type: "npm:^29.6.3" - pretty-format: "npm:^29.7.0" - checksum: 10/e3950e3ddd71e1d0c22924c51a300a1c2db6cf69ec1e51f95ccf424bcc070f78664813bef7aed4b16b96dfbdeea53fe358f8aeaaea84346ae15c3735758f1605 - languageName: node - linkType: hard - -"jest-matcher-utils@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-matcher-utils@npm:29.7.0" - dependencies: - chalk: "npm:^4.0.0" - jest-diff: "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - pretty-format: "npm:^29.7.0" - checksum: 10/981904a494299cf1e3baed352f8a3bd8b50a8c13a662c509b6a53c31461f94ea3bfeffa9d5efcfeb248e384e318c87de7e3baa6af0f79674e987482aa189af40 - languageName: node - linkType: hard - -"jest-message-util@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-message-util@npm:29.7.0" - dependencies: - "@babel/code-frame": "npm:^7.12.13" - "@jest/types": "npm:^29.6.3" - "@types/stack-utils": "npm:^2.0.0" - chalk: "npm:^4.0.0" - graceful-fs: "npm:^4.2.9" - micromatch: "npm:^4.0.4" - pretty-format: "npm:^29.7.0" - slash: "npm:^3.0.0" - stack-utils: "npm:^2.0.3" - checksum: 10/31d53c6ed22095d86bab9d14c0fa70c4a92c749ea6ceece82cf30c22c9c0e26407acdfbdb0231435dc85a98d6d65ca0d9cbcd25cd1abb377fe945e843fb770b9 - languageName: node - linkType: hard - -"jest-mock@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-mock@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - jest-util: "npm:^29.7.0" - checksum: 10/ae51d1b4f898724be5e0e52b2268a68fcd876d9b20633c864a6dd6b1994cbc48d62402b0f40f3a1b669b30ebd648821f086c26c08ffde192ced951ff4670d51c - languageName: node - linkType: hard - -"jest-pnp-resolver@npm:^1.2.2": - version: 1.2.3 - resolution: "jest-pnp-resolver@npm:1.2.3" - peerDependencies: - jest-resolve: "*" - peerDependenciesMeta: - jest-resolve: - optional: true - checksum: 10/db1a8ab2cb97ca19c01b1cfa9a9c8c69a143fde833c14df1fab0766f411b1148ff0df878adea09007ac6a2085ec116ba9a996a6ad104b1e58c20adbf88eed9b2 - languageName: node - linkType: hard - -"jest-regex-util@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-regex-util@npm:29.6.3" - checksum: 10/0518beeb9bf1228261695e54f0feaad3606df26a19764bc19541e0fc6e2a3737191904607fb72f3f2ce85d9c16b28df79b7b1ec9443aa08c3ef0e9efda6f8f2a - languageName: node - linkType: hard - -"jest-resolve-dependencies@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-resolve-dependencies@npm:29.7.0" - dependencies: - jest-regex-util: "npm:^29.6.3" - jest-snapshot: "npm:^29.7.0" - checksum: 10/1e206f94a660d81e977bcfb1baae6450cb4a81c92e06fad376cc5ea16b8e8c6ea78c383f39e95591a9eb7f925b6a1021086c38941aa7c1b8a6a813c2f6e93675 - languageName: node - linkType: hard - -"jest-resolve@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-resolve@npm:29.7.0" - dependencies: - chalk: "npm:^4.0.0" - graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.7.0" - jest-pnp-resolver: "npm:^1.2.2" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - resolve: "npm:^1.20.0" - resolve.exports: "npm:^2.0.0" - slash: "npm:^3.0.0" - checksum: 10/faa466fd9bc69ea6c37a545a7c6e808e073c66f46ab7d3d8a6ef084f8708f201b85d5fe1799789578b8b47fa1de47b9ee47b414d1863bc117a49e032ba77b7c7 - languageName: node - linkType: hard - -"jest-runner@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-runner@npm:29.7.0" - dependencies: - "@jest/console": "npm:^29.7.0" - "@jest/environment": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - chalk: "npm:^4.0.0" - emittery: "npm:^0.13.1" - graceful-fs: "npm:^4.2.9" - jest-docblock: "npm:^29.7.0" - jest-environment-node: "npm:^29.7.0" - jest-haste-map: "npm:^29.7.0" - jest-leak-detector: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-resolve: "npm:^29.7.0" - jest-runtime: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-watcher: "npm:^29.7.0" - jest-worker: "npm:^29.7.0" - p-limit: "npm:^3.1.0" - source-map-support: "npm:0.5.13" - checksum: 10/9d8748a494bd90f5c82acea99be9e99f21358263ce6feae44d3f1b0cd90991b5df5d18d607e73c07be95861ee86d1cbab2a3fc6ca4b21805f07ac29d47c1da1e - languageName: node - linkType: hard - -"jest-runtime@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-runtime@npm:29.7.0" - dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/fake-timers": "npm:^29.7.0" - "@jest/globals": "npm:^29.7.0" - "@jest/source-map": "npm:^29.6.3" - "@jest/test-result": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - chalk: "npm:^4.0.0" - cjs-module-lexer: "npm:^1.0.0" - collect-v8-coverage: "npm:^1.0.0" - glob: "npm:^7.1.3" - graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-mock: "npm:^29.7.0" - jest-regex-util: "npm:^29.6.3" - jest-resolve: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - slash: "npm:^3.0.0" - strip-bom: "npm:^4.0.0" - checksum: 10/59eb58eb7e150e0834a2d0c0d94f2a0b963ae7182cfa6c63f2b49b9c6ef794e5193ef1634e01db41420c36a94cefc512cdd67a055cd3e6fa2f41eaf0f82f5a20 - languageName: node - linkType: hard - -"jest-snapshot@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-snapshot@npm:29.7.0" - dependencies: - "@babel/core": "npm:^7.11.6" - "@babel/generator": "npm:^7.7.2" - "@babel/plugin-syntax-jsx": "npm:^7.7.2" - "@babel/plugin-syntax-typescript": "npm:^7.7.2" - "@babel/types": "npm:^7.3.3" - "@jest/expect-utils": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - babel-preset-current-node-syntax: "npm:^1.0.0" - chalk: "npm:^4.0.0" - expect: "npm:^29.7.0" - graceful-fs: "npm:^4.2.9" - jest-diff: "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - jest-matcher-utils: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - natural-compare: "npm:^1.4.0" - pretty-format: "npm:^29.7.0" - semver: "npm:^7.5.3" - checksum: 10/cb19a3948256de5f922d52f251821f99657339969bf86843bd26cf3332eae94883e8260e3d2fba46129a27c3971c1aa522490e460e16c7fad516e82d10bbf9f8 - languageName: node - linkType: hard - -"jest-util@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-util@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - chalk: "npm:^4.0.0" - ci-info: "npm:^3.2.0" - graceful-fs: "npm:^4.2.9" - picomatch: "npm:^2.2.3" - checksum: 10/30d58af6967e7d42bd903ccc098f3b4d3859ed46238fbc88d4add6a3f10bea00c226b93660285f058bc7a65f6f9529cf4eb80f8d4707f79f9e3a23686b4ab8f3 - languageName: node - linkType: hard - -"jest-validate@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-validate@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - camelcase: "npm:^6.2.0" - chalk: "npm:^4.0.0" - jest-get-type: "npm:^29.6.3" - leven: "npm:^3.1.0" - pretty-format: "npm:^29.7.0" - checksum: 10/8ee1163666d8eaa16d90a989edba2b4a3c8ab0ffaa95ad91b08ca42b015bfb70e164b247a5b17f9de32d096987cada63ed8491ab82761bfb9a28bc34b27ae161 - languageName: node - linkType: hard - -"jest-watcher@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-watcher@npm:29.7.0" - dependencies: - "@jest/test-result": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - ansi-escapes: "npm:^4.2.1" - chalk: "npm:^4.0.0" - emittery: "npm:^0.13.1" - jest-util: "npm:^29.7.0" - string-length: "npm:^4.0.1" - checksum: 10/4f616e0345676631a7034b1d94971aaa719f0cd4a6041be2aa299be437ea047afd4fe05c48873b7963f5687a2f6c7cbf51244be8b14e313b97bfe32b1e127e55 - languageName: node - linkType: hard - -"jest-worker@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-worker@npm:29.7.0" - dependencies: - "@types/node": "npm:*" - jest-util: "npm:^29.7.0" - merge-stream: "npm:^2.0.0" - supports-color: "npm:^8.0.0" - checksum: 10/364cbaef00d8a2729fc760227ad34b5e60829e0869bd84976bdfbd8c0d0f9c2f22677b3e6dd8afa76ed174765351cd12bae3d4530c62eefb3791055127ca9745 - languageName: node - linkType: hard - -"jest@npm:^29.7.0": - version: 29.7.0 - resolution: "jest@npm:29.7.0" - dependencies: - "@jest/core": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - import-local: "npm:^3.0.2" - jest-cli: "npm:^29.7.0" - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - bin: - jest: bin/jest.js - checksum: 10/97023d78446098c586faaa467fbf2c6b07ff06e2c85a19e3926adb5b0effe9ac60c4913ae03e2719f9c01ae8ffd8d92f6b262cedb9555ceeb5d19263d8c6362a - languageName: node - linkType: hard - -"js-tokens@npm:^4.0.0": - version: 4.0.0 - resolution: "js-tokens@npm:4.0.0" - checksum: 10/af37d0d913fb56aec6dc0074c163cc71cd23c0b8aad5c2350747b6721d37ba118af35abdd8b33c47ec2800de07dedb16a527ca9c530ee004093e04958bd0cbf2 - languageName: node - linkType: hard - -"js-yaml@npm:^3.13.1": - version: 3.14.1 - resolution: "js-yaml@npm:3.14.1" - dependencies: - argparse: "npm:^1.0.7" - esprima: "npm:^4.0.0" - bin: - js-yaml: bin/js-yaml.js - checksum: 10/9e22d80b4d0105b9899135365f746d47466ed53ef4223c529b3c0f7a39907743fdbd3c4379f94f1106f02755b5e90b2faaf84801a891135544e1ea475d1a1379 - languageName: node - linkType: hard - "jsbn@npm:1.1.0": version: 1.1.0 resolution: "jsbn@npm:1.1.0" @@ -3257,61 +1324,6 @@ __metadata: languageName: node linkType: hard -"jsesc@npm:^3.0.2": - version: 3.1.0 - resolution: "jsesc@npm:3.1.0" - bin: - jsesc: bin/jsesc - checksum: 10/20bd37a142eca5d1794f354db8f1c9aeb54d85e1f5c247b371de05d23a9751ecd7bd3a9c4fc5298ea6fa09a100dafb4190fa5c98c6610b75952c3487f3ce7967 - languageName: node - linkType: hard - -"json-parse-even-better-errors@npm:^2.3.0": - version: 2.3.1 - resolution: "json-parse-even-better-errors@npm:2.3.1" - checksum: 10/5f3a99009ed5f2a5a67d06e2f298cc97bc86d462034173308156f15b43a6e850be8511dc204b9b94566305da2947f7d90289657237d210351a39059ff9d666cf - languageName: node - linkType: hard - -"json5@npm:^2.2.3": - version: 2.2.3 - resolution: "json5@npm:2.2.3" - bin: - json5: lib/cli.js - checksum: 10/1db67b853ff0de3534085d630691d3247de53a2ed1390ba0ddff681ea43e9b3e30ecbdb65c5e9aab49435e44059c23dbd6fee8ee619419ba37465bb0dd7135da - languageName: node - linkType: hard - -"kleur@npm:^3.0.3": - version: 3.0.3 - resolution: "kleur@npm:3.0.3" - checksum: 10/0c0ecaf00a5c6173d25059c7db2113850b5457016dfa1d0e3ef26da4704fbb186b4938d7611246d86f0ddf1bccf26828daa5877b1f232a65e7373d0122a83e7f - languageName: node - linkType: hard - -"leven@npm:^3.1.0": - version: 3.1.0 - resolution: "leven@npm:3.1.0" - checksum: 10/638401d534585261b6003db9d99afd244dfe82d75ddb6db5c0df412842d5ab30b2ef18de471aaec70fe69a46f17b4ae3c7f01d8a4e6580ef7adb9f4273ad1e55 - languageName: node - linkType: hard - -"lines-and-columns@npm:^1.1.6": - version: 1.2.4 - resolution: "lines-and-columns@npm:1.2.4" - checksum: 10/0c37f9f7fa212b38912b7145e1cd16a5f3cd34d782441c3e6ca653485d326f58b3caccda66efce1c5812bde4961bbde3374fae4b0d11bf1226152337f3894aa5 - languageName: node - linkType: hard - -"locate-path@npm:^5.0.0": - version: 5.0.0 - resolution: "locate-path@npm:5.0.0" - dependencies: - p-locate: "npm:^4.1.0" - checksum: 10/83e51725e67517287d73e1ded92b28602e3ae5580b301fe54bfb76c0c723e3f285b19252e375712316774cf52006cb236aed5704692c32db0d5d089b69696e30 - languageName: node - linkType: hard - "log-symbols@npm:^6.0.0": version: 6.0.0 resolution: "log-symbols@npm:6.0.0" @@ -3346,15 +1358,6 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^5.1.1": - version: 5.1.1 - resolution: "lru-cache@npm:5.1.1" - dependencies: - yallist: "npm:^3.0.2" - checksum: 10/951d2673dcc64a7fb888bf3d13bc2fdf923faca97d89cdb405ba3dfff77e2b26e5798d405e78fcd7094c9e7b8b4dab2ddc5a4f8a11928af24a207b7c738ca3f8 - languageName: node - linkType: hard - "magic-string@npm:^0.30.17": version: 0.30.17 resolution: "magic-string@npm:0.30.17" @@ -3364,15 +1367,6 @@ __metadata: languageName: node linkType: hard -"make-dir@npm:^4.0.0": - version: 4.0.0 - resolution: "make-dir@npm:4.0.0" - dependencies: - semver: "npm:^7.5.3" - checksum: 10/bf0731a2dd3aab4db6f3de1585cea0b746bb73eb5a02e3d8d72757e376e64e6ada190b1eddcde5b2f24a81b688a9897efd5018737d05e02e2a671dda9cff8a8a - languageName: node - linkType: hard - "make-error@npm:^1.1.1": version: 1.3.6 resolution: "make-error@npm:1.3.6" @@ -3399,39 +1393,6 @@ __metadata: languageName: node linkType: hard -"makeerror@npm:1.0.12": - version: 1.0.12 - resolution: "makeerror@npm:1.0.12" - dependencies: - tmpl: "npm:1.0.5" - checksum: 10/4c66ddfc654537333da952c084f507fa4c30c707b1635344eb35be894d797ba44c901a9cebe914aa29a7f61357543ba09b09dddbd7f65b4aee756b450f169f40 - languageName: node - linkType: hard - -"merge-stream@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-stream@npm:2.0.0" - checksum: 10/6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 - languageName: node - linkType: hard - -"micromatch@npm:^4.0.4": - version: 4.0.8 - resolution: "micromatch@npm:4.0.8" - dependencies: - braces: "npm:^3.0.3" - picomatch: "npm:^2.3.1" - checksum: 10/6bf2a01672e7965eb9941d1f02044fad2bd12486b5553dc1116ff24c09a8723157601dc992e74c911d896175918448762df3b3fd0a6b61037dd1a9766ddfbf58 - languageName: node - linkType: hard - -"mimic-fn@npm:^2.1.0": - version: 2.1.0 - resolution: "mimic-fn@npm:2.1.0" - checksum: 10/d2421a3444848ce7f84bd49115ddacff29c15745db73f54041edc906c14b131a38d05298dae3081667627a59b2eb1ca4b436ff2e1b80f69679522410418b478a - languageName: node - linkType: hard - "mimic-function@npm:^5.0.0": version: 5.0.1 resolution: "mimic-function@npm:5.0.1" @@ -3439,15 +1400,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: "npm:^1.1.7" - checksum: 10/e0b25b04cd4ec6732830344e5739b13f8690f8a012d73445a4a19fbc623f5dd481ef7a5827fde25954cd6026fede7574cc54dc4643c99d6c6b653d6203f94634 - languageName: node - linkType: hard - "minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -3558,13 +1510,6 @@ __metadata: languageName: node linkType: hard -"natural-compare@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare@npm:1.4.0" - checksum: 10/23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d - languageName: node - linkType: hard - "negotiator@npm:^1.0.0": version: 1.0.0 resolution: "negotiator@npm:1.0.0" @@ -3592,20 +1537,6 @@ __metadata: languageName: node linkType: hard -"node-int64@npm:^0.4.0": - version: 0.4.0 - resolution: "node-int64@npm:0.4.0" - checksum: 10/b7afc2b65e56f7035b1a2eec57ae0fbdee7d742b1cdcd0f4387562b6527a011ab1cbe9f64cc8b3cca61e3297c9637c8bf61cec2e6b8d3a711d4b5267dfafbe02 - languageName: node - linkType: hard - -"node-releases@npm:^2.0.19": - version: 2.0.19 - resolution: "node-releases@npm:2.0.19" - checksum: 10/c2b33b4f0c40445aee56141f13ca692fa6805db88510e5bbb3baadb2da13e1293b738e638e15e4a8eb668bb9e97debb08e7a35409b477b5cc18f171d35a83045 - languageName: node - linkType: hard - "nopt@npm:^8.0.0": version: 8.1.0 resolution: "nopt@npm:8.1.0" @@ -3617,22 +1548,6 @@ __metadata: languageName: node linkType: hard -"normalize-path@npm:^3.0.0": - version: 3.0.0 - resolution: "normalize-path@npm:3.0.0" - checksum: 10/88eeb4da891e10b1318c4b2476b6e2ecbeb5ff97d946815ffea7794c31a89017c70d7f34b3c2ebf23ef4e9fc9fb99f7dffe36da22011b5b5c6ffa34f4873ec20 - languageName: node - linkType: hard - -"npm-run-path@npm:^4.0.1": - version: 4.0.1 - resolution: "npm-run-path@npm:4.0.1" - dependencies: - path-key: "npm:^3.0.0" - checksum: 10/5374c0cea4b0bbfdfae62da7bbdf1e1558d338335f4cacf2515c282ff358ff27b2ecb91ffa5330a8b14390ac66a1e146e10700440c1ab868208430f56b5f4d23 - languageName: node - linkType: hard - "object-inspect@npm:^1.12.3": version: 1.13.4 resolution: "object-inspect@npm:1.13.4" @@ -3640,24 +1555,6 @@ __metadata: languageName: node linkType: hard -"once@npm:^1.3.0": - version: 1.4.0 - resolution: "once@npm:1.4.0" - dependencies: - wrappy: "npm:1" - checksum: 10/cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 - languageName: node - linkType: hard - -"onetime@npm:^5.1.2": - version: 5.1.2 - resolution: "onetime@npm:5.1.2" - dependencies: - mimic-fn: "npm:^2.1.0" - checksum: 10/e9fd0695a01cf226652f0385bf16b7a24153dbbb2039f764c8ba6d2306a8506b0e4ce570de6ad99c7a6eb49520743afdb66edd95ee979c1a342554ed49a9aadd - languageName: node - linkType: hard - "onetime@npm:^7.0.0": version: 7.0.0 resolution: "onetime@npm:7.0.0" @@ -3684,33 +1581,6 @@ __metadata: languageName: node linkType: hard -"p-limit@npm:^2.2.0": - version: 2.3.0 - resolution: "p-limit@npm:2.3.0" - dependencies: - p-try: "npm:^2.0.0" - checksum: 10/84ff17f1a38126c3314e91ecfe56aecbf36430940e2873dadaa773ffe072dc23b7af8e46d4b6485d302a11673fe94c6b67ca2cfbb60c989848b02100d0594ac1 - languageName: node - linkType: hard - -"p-limit@npm:^3.1.0": - version: 3.1.0 - resolution: "p-limit@npm:3.1.0" - dependencies: - yocto-queue: "npm:^0.1.0" - checksum: 10/7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360 - languageName: node - linkType: hard - -"p-locate@npm:^4.1.0": - version: 4.1.0 - resolution: "p-locate@npm:4.1.0" - dependencies: - p-limit: "npm:^2.2.0" - checksum: 10/513bd14a455f5da4ebfcb819ef706c54adb09097703de6aeaa5d26fe5ea16df92b48d1ac45e01e3944ce1e6aa2a66f7f8894742b8c9d6e276e16cd2049a2b870 - languageName: node - linkType: hard - "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" @@ -3718,13 +1588,6 @@ __metadata: languageName: node linkType: hard -"p-try@npm:^2.0.0": - version: 2.2.0 - resolution: "p-try@npm:2.2.0" - checksum: 10/f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae - languageName: node - linkType: hard - "package-json-from-dist@npm:^1.0.0": version: 1.0.1 resolution: "package-json-from-dist@npm:1.0.1" @@ -3732,46 +1595,13 @@ __metadata: languageName: node linkType: hard -"parse-json@npm:^5.2.0": - version: 5.2.0 - resolution: "parse-json@npm:5.2.0" - dependencies: - "@babel/code-frame": "npm:^7.0.0" - error-ex: "npm:^1.3.1" - json-parse-even-better-errors: "npm:^2.3.0" - lines-and-columns: "npm:^1.1.6" - checksum: 10/62085b17d64da57f40f6afc2ac1f4d95def18c4323577e1eced571db75d9ab59b297d1d10582920f84b15985cbfc6b6d450ccbf317644cfa176f3ed982ad87e2 - languageName: node - linkType: hard - -"path-exists@npm:^4.0.0": - version: 4.0.0 - resolution: "path-exists@npm:4.0.0" - checksum: 10/505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 - languageName: node - linkType: hard - -"path-is-absolute@npm:^1.0.0": - version: 1.0.1 - resolution: "path-is-absolute@npm:1.0.1" - checksum: 10/060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 - languageName: node - linkType: hard - -"path-key@npm:^3.0.0, path-key@npm:^3.1.0": +"path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" checksum: 10/55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 languageName: node linkType: hard -"path-parse@npm:^1.0.7": - version: 1.0.7 - resolution: "path-parse@npm:1.0.7" - checksum: 10/49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a - languageName: node - linkType: hard - "path-scurry@npm:^1.11.1": version: 1.11.1 resolution: "path-scurry@npm:1.11.1" @@ -3803,13 +1633,6 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^2.0.4, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": - version: 2.3.1 - resolution: "picomatch@npm:2.3.1" - checksum: 10/60c2595003b05e4535394d1da94850f5372c9427ca4413b71210f437f7b2ca091dbd611c45e8b37d10036fa8eade25c1b8951654f9d3973bfa66a2ff4d3b08bc - languageName: node - linkType: hard - "picomatch@npm:^4.0.2": version: 4.0.2 resolution: "picomatch@npm:4.0.2" @@ -3817,22 +1640,6 @@ __metadata: languageName: node linkType: hard -"pirates@npm:^4.0.4": - version: 4.0.7 - resolution: "pirates@npm:4.0.7" - checksum: 10/2427f371366081ae42feb58214f04805d6b41d6b84d74480ebcc9e0ddbd7105a139f7c653daeaf83ad8a1a77214cf07f64178e76de048128fec501eab3305a96 - languageName: node - linkType: hard - -"pkg-dir@npm:^4.2.0": - version: 4.2.0 - resolution: "pkg-dir@npm:4.2.0" - dependencies: - find-up: "npm:^4.0.0" - checksum: 10/9863e3f35132bf99ae1636d31ff1e1e3501251d480336edb1c211133c8d58906bed80f154a1d723652df1fda91e01c7442c2eeaf9dc83157c7ae89087e43c8d6 - languageName: node - linkType: hard - "postcss@npm:^8.5.3": version: 8.5.3 resolution: "postcss@npm:8.5.3" @@ -3844,17 +1651,6 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": - version: 29.7.0 - resolution: "pretty-format@npm:29.7.0" - dependencies: - "@jest/schemas": "npm:^29.6.3" - ansi-styles: "npm:^5.0.0" - react-is: "npm:^18.0.0" - checksum: 10/dea96bc83c83cd91b2bfc55757b6b2747edcaac45b568e46de29deee80742f17bc76fe8898135a70d904f4928eafd8bb693cd1da4896e8bdd3c5e82cadf1d2bb - languageName: node - linkType: hard - "proc-log@npm:^5.0.0": version: 5.0.0 resolution: "proc-log@npm:5.0.0" @@ -3872,86 +1668,13 @@ __metadata: languageName: node linkType: hard -"prompts@npm:^2.0.1": - version: 2.4.2 - resolution: "prompts@npm:2.4.2" - dependencies: - kleur: "npm:^3.0.3" - sisteransi: "npm:^1.0.5" - checksum: 10/c52536521a4d21eff4f2f2aa4572446cad227464066365a7167e52ccf8d9839c099f9afec1aba0eed3d5a2514b3e79e0b3e7a1dc326b9acde6b75d27ed74b1a9 - languageName: node - linkType: hard - -"pure-rand@npm:^6.0.0, pure-rand@npm:^6.1.0": +"pure-rand@npm:^6.1.0": version: 6.1.0 resolution: "pure-rand@npm:6.1.0" checksum: 10/256aa4bcaf9297256f552914e03cbdb0039c8fe1db11fa1e6d3f80790e16e563eb0a859a1e61082a95e224fc0c608661839439f8ecc6a3db4e48d46d99216ee4 languageName: node linkType: hard -"react-is@npm:^18.0.0": - version: 18.3.1 - resolution: "react-is@npm:18.3.1" - checksum: 10/d5f60c87d285af24b1e1e7eaeb123ec256c3c8bdea7061ab3932e3e14685708221bf234ec50b21e10dd07f008f1b966a2730a0ce4ff67905b3872ff2042aec22 - languageName: node - linkType: hard - -"require-directory@npm:^2.1.1": - version: 2.1.1 - resolution: "require-directory@npm:2.1.1" - checksum: 10/a72468e2589270d91f06c7d36ec97a88db53ae5d6fe3787fadc943f0b0276b10347f89b363b2a82285f650bdcc135ad4a257c61bdd4d00d6df1fa24875b0ddaf - languageName: node - linkType: hard - -"resolve-cwd@npm:^3.0.0": - version: 3.0.0 - resolution: "resolve-cwd@npm:3.0.0" - dependencies: - resolve-from: "npm:^5.0.0" - checksum: 10/546e0816012d65778e580ad62b29e975a642989108d9a3c5beabfb2304192fa3c9f9146fbdfe213563c6ff51975ae41bac1d3c6e047dd9572c94863a057b4d81 - languageName: node - linkType: hard - -"resolve-from@npm:^5.0.0": - version: 5.0.0 - resolution: "resolve-from@npm:5.0.0" - checksum: 10/be18a5e4d76dd711778664829841cde690971d02b6cbae277735a09c1c28f407b99ef6ef3cd585a1e6546d4097b28df40ed32c4a287b9699dcf6d7f208495e23 - languageName: node - linkType: hard - -"resolve.exports@npm:^2.0.0": - version: 2.0.3 - resolution: "resolve.exports@npm:2.0.3" - checksum: 10/536efee0f30a10fac8604e6cdc7844dbc3f4313568d09f06db4f7ed8a5b8aeb8585966fe975083d1f2dfbc87cf5f8bc7ab65a5c23385c14acbb535ca79f8398a - languageName: node - linkType: hard - -"resolve@npm:^1.20.0": - version: 1.22.10 - resolution: "resolve@npm:1.22.10" - dependencies: - is-core-module: "npm:^2.16.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10/0a398b44da5c05e6e421d70108822c327675febb880eebe905587628de401854c61d5df02866ff34fc4cb1173a51c9f0e84a94702738df3611a62e2acdc68181 - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A^1.20.0#optional!builtin": - version: 1.22.10 - resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.16.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10/d4d878bfe3702d215ea23e75e0e9caf99468e3db76f5ca100d27ebdc527366fee3877e54bce7d47cc72ca8952fc2782a070d238bfa79a550eeb0082384c3b81a - languageName: node - linkType: hard - "restore-cursor@npm:^5.0.0": version: 5.1.0 resolution: "restore-cursor@npm:5.1.0" @@ -4068,16 +1791,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^6.3.0, semver@npm:^6.3.1": - version: 6.3.1 - resolution: "semver@npm:6.3.1" - bin: - semver: bin/semver.js - checksum: 10/1ef3a85bd02a760c6ef76a45b8c1ce18226de40831e02a00bad78485390b98b6ccaa31046245fc63bba4a47a6a592b6c7eedc65cc47126e60489f9cc1ce3ed7e - languageName: node - linkType: hard - -"semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4": +"semver@npm:^7.3.5": version: 7.7.2 resolution: "semver@npm:7.7.2" bin: @@ -4109,13 +1823,6 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: 10/a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 - languageName: node - linkType: hard - "signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" @@ -4123,20 +1830,6 @@ __metadata: languageName: node linkType: hard -"sisteransi@npm:^1.0.5": - version: 1.0.5 - resolution: "sisteransi@npm:1.0.5" - checksum: 10/aba6438f46d2bfcef94cf112c835ab395172c75f67453fe05c340c770d3c402363018ae1ab4172a1026a90c47eaccf3af7b6ff6fa749a680c2929bd7fa2b37a4 - languageName: node - linkType: hard - -"slash@npm:^3.0.0": - version: 3.0.0 - resolution: "slash@npm:3.0.0" - checksum: 10/94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c - languageName: node - linkType: hard - "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" @@ -4172,23 +1865,6 @@ __metadata: languageName: node linkType: hard -"source-map-support@npm:0.5.13": - version: 0.5.13 - resolution: "source-map-support@npm:0.5.13" - dependencies: - buffer-from: "npm:^1.0.0" - source-map: "npm:^0.6.0" - checksum: 10/d1514a922ac9c7e4786037eeff6c3322f461cd25da34bb9fefb15387b3490531774e6e31d95ab6d5b84a3e139af9c3a570ccaee6b47bd7ea262691ed3a8bc34e - languageName: node - linkType: hard - -"source-map@npm:^0.6.0, source-map@npm:^0.6.1": - version: 0.6.1 - resolution: "source-map@npm:0.6.1" - checksum: 10/59ef7462f1c29d502b3057e822cdbdae0b0e565302c4dd1a95e11e793d8d9d62006cdc10e0fd99163ca33ff2071360cf50ee13f90440806e7ed57d81cba2f7ff - languageName: node - linkType: hard - "sprintf-js@npm:^1.1.3": version: 1.1.3 resolution: "sprintf-js@npm:1.1.3" @@ -4196,13 +1872,6 @@ __metadata: languageName: node linkType: hard -"sprintf-js@npm:~1.0.2": - version: 1.0.3 - resolution: "sprintf-js@npm:1.0.3" - checksum: 10/c34828732ab8509c2741e5fd1af6b767c3daf2c642f267788f933a65b1614943c282e74c4284f4fa749c264b18ee016a0d37a3e5b73aee446da46277d3a85daa - languageName: node - linkType: hard - "ssri@npm:^12.0.0": version: 12.0.0 resolution: "ssri@npm:12.0.0" @@ -4212,15 +1881,6 @@ __metadata: languageName: node linkType: hard -"stack-utils@npm:^2.0.3": - version: 2.0.6 - resolution: "stack-utils@npm:2.0.6" - dependencies: - escape-string-regexp: "npm:^2.0.0" - checksum: 10/cdc988acbc99075b4b036ac6014e5f1e9afa7e564482b687da6384eee6a1909d7eaffde85b0a17ffbe186c5247faf6c2b7544e802109f63b72c7be69b13151bb - languageName: node - linkType: hard - "stackback@npm:0.0.2": version: 0.0.2 resolution: "stackback@npm:0.0.2" @@ -4242,17 +1902,7 @@ __metadata: languageName: node linkType: hard -"string-length@npm:^4.0.1": - version: 4.0.2 - resolution: "string-length@npm:4.0.2" - dependencies: - char-regex: "npm:^1.0.2" - strip-ansi: "npm:^6.0.0" - checksum: 10/ce85533ef5113fcb7e522bcf9e62cb33871aa99b3729cec5595f4447f660b0cefd542ca6df4150c97a677d58b0cb727a3fe09ac1de94071d05526c73579bf505 - languageName: node - linkType: hard - -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -4303,52 +1953,6 @@ __metadata: languageName: node linkType: hard -"strip-bom@npm:^4.0.0": - version: 4.0.0 - resolution: "strip-bom@npm:4.0.0" - checksum: 10/9dbcfbaf503c57c06af15fe2c8176fb1bf3af5ff65003851a102749f875a6dbe0ab3b30115eccf6e805e9d756830d3e40ec508b62b3f1ddf3761a20ebe29d3f3 - languageName: node - linkType: hard - -"strip-final-newline@npm:^2.0.0": - version: 2.0.0 - resolution: "strip-final-newline@npm:2.0.0" - checksum: 10/69412b5e25731e1938184b5d489c32e340605bb611d6140344abc3421b7f3c6f9984b21dff296dfcf056681b82caa3bb4cc996a965ce37bcfad663e92eae9c64 - languageName: node - linkType: hard - -"strip-json-comments@npm:^3.1.1": - version: 3.1.1 - resolution: "strip-json-comments@npm:3.1.1" - checksum: 10/492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 - languageName: node - linkType: hard - -"supports-color@npm:^7.1.0": - version: 7.2.0 - resolution: "supports-color@npm:7.2.0" - dependencies: - has-flag: "npm:^4.0.0" - checksum: 10/c8bb7afd564e3b26b50ca6ee47572c217526a1389fe018d00345856d4a9b08ffbd61fadaf283a87368d94c3dcdb8f5ffe2650a5a65863e21ad2730ca0f05210a - languageName: node - linkType: hard - -"supports-color@npm:^8.0.0": - version: 8.1.1 - resolution: "supports-color@npm:8.1.1" - dependencies: - has-flag: "npm:^4.0.0" - checksum: 10/157b534df88e39c5518c5e78c35580c1eca848d7dbaf31bbe06cdfc048e22c7ff1a9d046ae17b25691128f631a51d9ec373c1b740c12ae4f0de6e292037e4282 - languageName: node - linkType: hard - -"supports-preserve-symlinks-flag@npm:^1.0.0": - version: 1.0.0 - resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 10/a9dc19ae2220c952bd2231d08ddeecb1b0328b61e72071ff4000c8384e145cc07c1c0bdb3b5a1cb06e186a7b2790f1dee793418b332f6ddf320de25d9125be7e - languageName: node - linkType: hard - "tar@npm:^7.4.3": version: 7.4.3 resolution: "tar@npm:7.4.3" @@ -4363,17 +1967,6 @@ __metadata: languageName: node linkType: hard -"test-exclude@npm:^6.0.0": - version: 6.0.0 - resolution: "test-exclude@npm:6.0.0" - dependencies: - "@istanbuljs/schema": "npm:^0.1.2" - glob: "npm:^7.1.4" - minimatch: "npm:^3.0.4" - checksum: 10/8fccb2cb6c8fcb6bb4115394feb833f8b6cf4b9503ec2485c2c90febf435cac62abe882a0c5c51a37b9bbe70640cdd05acf5f45e486ac4583389f4b0855f69e5 - languageName: node - linkType: hard - "tinybench@npm:^2.9.0": version: 2.9.0 resolution: "tinybench@npm:2.9.0" @@ -4419,22 +2012,6 @@ __metadata: languageName: node linkType: hard -"tmpl@npm:1.0.5": - version: 1.0.5 - resolution: "tmpl@npm:1.0.5" - checksum: 10/cd922d9b853c00fe414c5a774817be65b058d54a2d01ebb415840960406c669a0fc632f66df885e24cb022ec812739199ccbdb8d1164c3e513f85bfca5ab2873 - languageName: node - linkType: hard - -"to-regex-range@npm:^5.0.1": - version: 5.0.1 - resolution: "to-regex-range@npm:5.0.1" - dependencies: - is-number: "npm:^7.0.0" - checksum: 10/10dda13571e1f5ad37546827e9b6d4252d2e0bc176c24a101252153ef435d83696e2557fe128c4678e4e78f5f01e83711c703eef9814eb12dab028580d45980a - languageName: node - linkType: hard - "ts-node@npm:^10.9.2": version: 10.9.2 resolution: "ts-node@npm:10.9.2" @@ -4544,20 +2121,6 @@ __metadata: languageName: node linkType: hard -"type-detect@npm:4.0.8": - version: 4.0.8 - resolution: "type-detect@npm:4.0.8" - checksum: 10/5179e3b8ebc51fce1b13efb75fdea4595484433f9683bbc2dca6d99789dba4e602ab7922d2656f2ce8383987467f7770131d4a7f06a26287db0615d2f4c4ce7d - languageName: node - linkType: hard - -"type-fest@npm:^0.21.3": - version: 0.21.3 - resolution: "type-fest@npm:0.21.3" - checksum: 10/f4254070d9c3d83a6e573bcb95173008d73474ceadbbf620dd32d273940ca18734dff39c2b2480282df9afe5d1675ebed5499a00d791758748ea81f61a38961f - languageName: node - linkType: hard - "typescript@npm:^5.2.2, typescript@npm:^5.8.2": version: 5.8.3 resolution: "typescript@npm:5.8.3" @@ -4610,20 +2173,6 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.1.3": - version: 1.1.3 - resolution: "update-browserslist-db@npm:1.1.3" - dependencies: - escalade: "npm:^3.2.0" - picocolors: "npm:^1.1.1" - peerDependencies: - browserslist: ">= 4.21.0" - bin: - update-browserslist-db: cli.js - checksum: 10/87af2776054ffb9194cf95e0201547d041f72ee44ce54b144da110e65ea7ca01379367407ba21de5c9edd52c74d95395366790de67f3eb4cc4afa0fe4424e76f - languageName: node - linkType: hard - "v8-compile-cache-lib@npm:^3.0.1": version: 3.0.1 resolution: "v8-compile-cache-lib@npm:3.0.1" @@ -4631,17 +2180,6 @@ __metadata: languageName: node linkType: hard -"v8-to-istanbul@npm:^9.0.1": - version: 9.3.0 - resolution: "v8-to-istanbul@npm:9.3.0" - dependencies: - "@jridgewell/trace-mapping": "npm:^0.3.12" - "@types/istanbul-lib-coverage": "npm:^2.0.1" - convert-source-map: "npm:^2.0.0" - checksum: 10/fb1d70f1176cb9dc46cabbb3fd5c52c8f3e8738b61877b6e7266029aed0870b04140e3f9f4550ac32aebcfe1d0f38b0bac57e1e8fb97d68fec82f2b416148166 - languageName: node - linkType: hard - "vite-node@npm:3.1.3": version: 3.1.3 resolution: "vite-node@npm:3.1.3" @@ -4766,15 +2304,6 @@ __metadata: languageName: node linkType: hard -"walker@npm:^1.0.8": - version: 1.0.8 - resolution: "walker@npm:1.0.8" - dependencies: - makeerror: "npm:1.0.12" - checksum: 10/ad7a257ea1e662e57ef2e018f97b3c02a7240ad5093c392186ce0bcf1f1a60bbadd520d073b9beb921ed99f64f065efb63dfc8eec689a80e569f93c1c5d5e16c - languageName: node - linkType: hard - "which@npm:^2.0.1": version: 2.0.2 resolution: "which@npm:2.0.2" @@ -4809,7 +2338,7 @@ __metadata: languageName: node linkType: hard -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" dependencies: @@ -4831,37 +2360,6 @@ __metadata: languageName: node linkType: hard -"wrappy@npm:1": - version: 1.0.2 - resolution: "wrappy@npm:1.0.2" - checksum: 10/159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 - languageName: node - linkType: hard - -"write-file-atomic@npm:^4.0.2": - version: 4.0.2 - resolution: "write-file-atomic@npm:4.0.2" - dependencies: - imurmurhash: "npm:^0.1.4" - signal-exit: "npm:^3.0.7" - checksum: 10/3be1f5508a46c190619d5386b1ac8f3af3dbe951ed0f7b0b4a0961eed6fc626bd84b50cf4be768dabc0a05b672f5d0c5ee7f42daa557b14415d18c3a13c7d246 - languageName: node - linkType: hard - -"y18n@npm:^5.0.5": - version: 5.0.8 - resolution: "y18n@npm:5.0.8" - checksum: 10/5f1b5f95e3775de4514edbb142398a2c37849ccfaf04a015be5d75521e9629d3be29bd4432d23c57f37e5b61ade592fb0197022e9993f81a06a5afbdcda9346d - languageName: node - linkType: hard - -"yallist@npm:^3.0.2": - version: 3.1.1 - resolution: "yallist@npm:3.1.1" - checksum: 10/9af0a4329c3c6b779ac4736c69fae4190ac03029fa27c1aef4e6bcc92119b73dea6fe5db5fe881fb0ce2a0e9539a42cdf60c7c21eda04d1a0b8c082e38509efb - languageName: node - linkType: hard - "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" @@ -4876,28 +2374,6 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^21.1.1": - version: 21.1.1 - resolution: "yargs-parser@npm:21.1.1" - checksum: 10/9dc2c217ea3bf8d858041252d43e074f7166b53f3d010a8c711275e09cd3d62a002969a39858b92bbda2a6a63a585c7127014534a560b9c69ed2d923d113406e - languageName: node - linkType: hard - -"yargs@npm:^17.3.1": - version: 17.7.2 - resolution: "yargs@npm:17.7.2" - dependencies: - cliui: "npm:^8.0.1" - escalade: "npm:^3.1.1" - get-caller-file: "npm:^2.0.5" - require-directory: "npm:^2.1.1" - string-width: "npm:^4.2.3" - y18n: "npm:^5.0.5" - yargs-parser: "npm:^21.1.1" - checksum: 10/abb3e37678d6e38ea85485ed86ebe0d1e3464c640d7d9069805ea0da12f69d5a32df8e5625e370f9c96dd1c2dc088ab2d0a4dd32af18222ef3c4224a19471576 - languageName: node - linkType: hard - "yn@npm:3.1.1": version: 3.1.1 resolution: "yn@npm:3.1.1" @@ -4905,13 +2381,6 @@ __metadata: languageName: node linkType: hard -"yocto-queue@npm:^0.1.0": - version: 0.1.0 - resolution: "yocto-queue@npm:0.1.0" - checksum: 10/f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 - languageName: node - linkType: hard - "yoctocolors@npm:^2.1.1": version: 2.1.1 resolution: "yoctocolors@npm:2.1.1" From 038d939ab48190a91b0f47d920122aec6649174c Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 18 May 2025 21:35:49 -0500 Subject: [PATCH 104/282] add vitest imports to test --- contracts/erc721/src/test/erc721.test.ts | 80 ------------------------ 1 file changed, 80 deletions(-) delete mode 100644 contracts/erc721/src/test/erc721.test.ts diff --git a/contracts/erc721/src/test/erc721.test.ts b/contracts/erc721/src/test/erc721.test.ts deleted file mode 100644 index 2e15385e..00000000 --- a/contracts/erc721/src/test/erc721.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; -import { beforeEach, describe, expect, it } from 'vitest'; -import { ERC721Simulator } from './simulators/ERC721Simulator'; -import type { MaybeString } from './types/string'; -import {encodeToPK, createEitherTestContractAddress, createEitherTestUser} from './utils/address'; - -const NO_STRING: MaybeString = { - is_some: false, - value: '' -}; -const NAME: MaybeString = { - is_some: true, - value: "NAME" -}; -const SYMBOL: MaybeString = { - is_some: true, - value: "SYMBOL" -}; - -const TOKENID: bigint = BigInt(1); - -const AMOUNT: bigint = BigInt(1); -const MAX_UINT128 = BigInt(2 ** 128) - BigInt(1); - -const OWNER = String(Buffer.from("OWNER", 'ascii').toString('hex')).padStart(64, '0'); -const SPENDER = String(Buffer.from("SPENDER", 'ascii').toString('hex')).padStart(64, '0'); -const UNAUTHORIZED = String(Buffer.from("UNAUTHORIZED", 'ascii').toString('hex')).padStart(64, '0'); -const ZERO = String().padStart(64, '0'); -const Z_OWNER = encodeToPK('OWNER'); -const EITHER_Z_OWNER = createEitherTestUser('OWNER'); -const Z_RECIPIENT = createEitherTestUser('RECIPIENT'); -const Z_SPENDER = createEitherTestUser('SPENDER'); -const Z_OTHER = createEitherTestUser('OTHER'); -const SOME_CONTRACT = createEitherTestContractAddress('SOME_CONTRACT'); - -let token: ERC721Simulator; -let caller: CoinPublicKey; - -describe('ERC721', () => { - describe('initializer and metadata', () => { - it('should initialize metadata', () => { - token = new ERC721Simulator(NAME, SYMBOL); - - expect(token.name()).toEqual(NAME); - expect(token.symbol()).toEqual(SYMBOL); - }); - - it('should initialize empty metadata', () => { - token = new ERC721Simulator(NO_STRING, NO_STRING); - - expect(token.name()).toEqual(NO_STRING); - expect(token.symbol()).toEqual(NO_STRING); - }); - }); - - beforeEach(() => { - token = new ERC721Simulator(NAME, SYMBOL); - }); - - describe('balanceOf', () => { - it('should return zero when requested account has no balance', () => { - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - - it('should return balance when requested account has tokens', () => { - token._mint(EITHER_Z_OWNER, AMOUNT); - expect(token.balanceOf(EITHER_Z_OWNER.left)).toEqual(AMOUNT); - }); - }); - - describe('ownerOf', () => { - it('should throw if tokenId does not exist', () => { - expect(() => { - token.ownerOf(TOKENID); - }).toThrow('ERC721: Nonexistent Token'); - }) - }) - - -}); From 7b5c1b01e73fd9554b02f33d1ea87ca0eb53611f Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 18 May 2025 21:49:25 -0500 Subject: [PATCH 105/282] remove barrel files --- contracts/erc721/src/test/types/string.ts | 4 -- contracts/erc721/src/test/utils/test.ts | 68 ----------------------- 2 files changed, 72 deletions(-) delete mode 100644 contracts/erc721/src/test/types/string.ts delete mode 100644 contracts/erc721/src/test/utils/test.ts diff --git a/contracts/erc721/src/test/types/string.ts b/contracts/erc721/src/test/types/string.ts deleted file mode 100644 index 430a139e..00000000 --- a/contracts/erc721/src/test/types/string.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type MaybeString = { - is_some: boolean; - value: string; -}; diff --git a/contracts/erc721/src/test/utils/test.ts b/contracts/erc721/src/test/utils/test.ts deleted file mode 100644 index d467e572..00000000 --- a/contracts/erc721/src/test/utils/test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - QueryContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types/test'; - -/** - * Constructs a `CircuitContext` from the given state and sender information. - * - * This is typically used at runtime to provide the necessary context - * for executing circuits, including contract state, private state, - * sender identity, and transaction data. - * - * @template P - The type of the contract's private state. - * @param privateState - The current private state of the contract. - * @param contractState - The full contract state, including public and private data. - * @param sender - The public key of the sender (used in the circuit). - * @param contractAddress - The address of the deployed contract. - * @returns A fully populated `CircuitContext` for circuit execution. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContext

( - privateState: P, - contractState: ContractState, - sender: CoinPublicKey, - contractAddress: ContractAddress, -): CircuitContext

{ - return { - originalState: contractState, - currentPrivateState: privateState, - transactionContext: new QueryContext(contractState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} - -/** - * Prepares a new `CircuitContext` using the given sender and contract. - * - * Useful for mocking or updating the circuit context with a custom sender. - * - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - * @template C - The specific type of the contract implementing `MockContract`. - * @param contract - The contract instance implementing `MockContract`. - * @param sender - The public key to set as the sender in the new circuit context. - * @returns A new `CircuitContext` with the sender and updated context values. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContextSender< - P, - L, - C extends IContractSimulator, ->(contract: C, sender: CoinPublicKey): CircuitContext

{ - const currentPrivateState = contract.getCurrentPrivateState(); - const originalState = contract.getCurrentContractState(); - const contractAddress = contract.contractAddress; - - return { - originalState, - currentPrivateState, - transactionContext: new QueryContext(originalState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} From 59ba06f4d080ae644ac674bdf93148dbae384113 Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 18 May 2025 21:52:10 -0500 Subject: [PATCH 106/282] fix fmt and lint --- compact/package.json | 5 +-- .../erc721/src/witnesses/ERC721Witnesses.ts | 32 +++++++++++-------- .../src/test/simulators/UtilsSimulator.ts | 17 +++++----- contracts/utils/src/test/utils.test.ts | 14 +++++--- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/compact/package.json b/compact/package.json index 8ee95ee9..ac08934d 100644 --- a/compact/package.json +++ b/compact/package.json @@ -2,10 +2,7 @@ "packageManager": "yarn@4.1.0", "name": "@openzeppelin-midnight/compact", "version": "0.0.1", - "keywords": [ - "compact", - "compiler" - ], + "keywords": ["compact", "compiler"], "author": "", "license": "MIT", "description": "Compact fetcher", diff --git a/contracts/erc721/src/witnesses/ERC721Witnesses.ts b/contracts/erc721/src/witnesses/ERC721Witnesses.ts index 273ca2e0..da3c60e6 100644 --- a/contracts/erc721/src/witnesses/ERC721Witnesses.ts +++ b/contracts/erc721/src/witnesses/ERC721Witnesses.ts @@ -2,20 +2,24 @@ import type * as Contract from "../artifacts/MockERC721/contract/index.cjs"; import type { WitnessContext } from "@midnight-ntwrk/compact-runtime"; export type ERC721PrivateState = { - tokenURI: string + tokenURI: string; }; export const ERC721Witnesses = { - /** - * @description A mock implementation of the computeTokenURI witness function - * - * @dev This function should be modified to meet the needs of your application - * - * @param {ERC721PrivateState} privateState The private state of the contract - * @param {string} baseURI The baseURI which is the empty string by default - * @returns {[ERC721PrivateState, string]} A tuple of the new private state and the declared return value - */ - computeTokenURI({ privateState }: WitnessContext, baseURI: string, tokenId: bigint): [ERC721PrivateState, string] { - return [privateState, baseURI + privateState.tokenURI + tokenId.toString()]; - } -} + /** + * @description A mock implementation of the computeTokenURI witness function + * + * @dev This function should be modified to meet the needs of your application + * + * @param {ERC721PrivateState} privateState The private state of the contract + * @param {string} baseURI The baseURI which is the empty string by default + * @returns {[ERC721PrivateState, string]} A tuple of the new private state and the declared return value + */ + computeTokenURI( + { privateState }: WitnessContext, + baseURI: string, + tokenId: bigint, + ): [ERC721PrivateState, string] { + return [privateState, baseURI + privateState.tokenURI + tokenId.toString()]; + }, +}; diff --git a/contracts/utils/src/test/simulators/UtilsSimulator.ts b/contracts/utils/src/test/simulators/UtilsSimulator.ts index a09d7026..6a618fa3 100644 --- a/contracts/utils/src/test/simulators/UtilsSimulator.ts +++ b/contracts/utils/src/test/simulators/UtilsSimulator.ts @@ -24,14 +24,9 @@ import type { IContractSimulator } from '../types/test'; * @template P - The private state type, fixed to UtilsPrivateState. * @template L - The ledger type, fixed to Contract.Ledger. */ -<<<<<<< HEAD:contracts/utils/src/test/UtilsSimulator.ts -export class UtilsContractSimulator - implements IContractSimulator { -======= export class UtilsSimulator implements IContractSimulator { ->>>>>>> b6f5215 (Add pausable (#22)):contracts/utils/src/test/simulators/UtilsSimulator.ts /** @description The underlying contract instance managing contract logic. */ readonly contract: MockUtils; @@ -102,18 +97,22 @@ export class UtilsSimulator } /** - * @description Returns whether `keyOrAddress` is equal to `other`. Assumes that a ZswapCoinPublicKey + * @description Returns whether `keyOrAddress` is equal to `other`. Assumes that a ZswapCoinPublicKey * and a ContractAddress can never be equal * * @public - * @param {Either} keyOrAddress The target value to check + * @param {Either} keyOrAddress The target value to check * @param {Either} other The other value to check * @returns {boolean} Returns true if `keyOrAddress` is is equal to `other`. */ public isKeyOrAddressEqual( keyOrAddress: Either, - other: Either + other: Either, ): boolean { - return this.contract.circuits.isKeyOrAddressEqual(this.circuitContext, keyOrAddress, other).result; + return this.contract.circuits.isKeyOrAddressEqual( + this.circuitContext, + keyOrAddress, + other, + ).result; } } diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index f99953ac..f1ea12b2 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -4,8 +4,10 @@ import * as contractUtils from './utils/address'; const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); -const SOME_CONTRACT = contractUtils.createEitherTestContractAddress('SOME_CONTRACT'); -const OTHER_CONTRACT = contractUtils.createEitherTestContractAddress('OTHER_CONTRACT'); +const SOME_CONTRACT = + contractUtils.createEitherTestContractAddress('SOME_CONTRACT'); +const OTHER_CONTRACT = + contractUtils.createEitherTestContractAddress('OTHER_CONTRACT'); let contract: UtilsSimulator; @@ -38,7 +40,9 @@ describe('Utils', () => { }); it('should return true for two matching contract addresses', () => { - expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, SOME_CONTRACT)).toBeTruthy(); + expect( + contract.isKeyOrAddressEqual(SOME_CONTRACT, SOME_CONTRACT), + ).toBeTruthy(); }); it('should return false for two different pubkeys', () => { @@ -46,7 +50,9 @@ describe('Utils', () => { }); it('should return false for two different contract addresses', () => { - expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, OTHER_CONTRACT)).toBeFalsy(); + expect( + contract.isKeyOrAddressEqual(SOME_CONTRACT, OTHER_CONTRACT), + ).toBeFalsy(); }); }); }); From f938354a94619a92b71e1118f228caa9771bbcf7 Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 18 May 2025 22:34:37 -0500 Subject: [PATCH 107/282] add vitest config, remove eslint and jest from erc721 --- compact/package.json | 5 ++++- contracts/erc721/vitest.config.ts | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 contracts/erc721/vitest.config.ts diff --git a/compact/package.json b/compact/package.json index ac08934d..8ee95ee9 100644 --- a/compact/package.json +++ b/compact/package.json @@ -2,7 +2,10 @@ "packageManager": "yarn@4.1.0", "name": "@openzeppelin-midnight/compact", "version": "0.0.1", - "keywords": ["compact", "compiler"], + "keywords": [ + "compact", + "compiler" + ], "author": "", "license": "MIT", "description": "Compact fetcher", diff --git a/contracts/erc721/vitest.config.ts b/contracts/erc721/vitest.config.ts new file mode 100644 index 00000000..785b792e --- /dev/null +++ b/contracts/erc721/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['src/test/**/*.test.ts'], + reporters: 'verbose', + }, +}); From 3b30b97110314dc68ab3ff3c57c6ba3cad374514 Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 18 May 2025 22:35:13 -0500 Subject: [PATCH 108/282] fix fmt --- compact/package.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compact/package.json b/compact/package.json index 8ee95ee9..ac08934d 100644 --- a/compact/package.json +++ b/compact/package.json @@ -2,10 +2,7 @@ "packageManager": "yarn@4.1.0", "name": "@openzeppelin-midnight/compact", "version": "0.0.1", - "keywords": [ - "compact", - "compiler" - ], + "keywords": ["compact", "compiler"], "author": "", "license": "MIT", "description": "Compact fetcher", From dc15375d035d788802a0e43d9781f02351f4acc8 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Wed, 21 May 2025 19:01:42 -0500 Subject: [PATCH 109/282] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> Signed-off-by: Andrew Fleming --- contracts/utils/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 99d724da..8a4e7b55 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -29,7 +29,7 @@ "devDependencies": { "@openzeppelin-midnight/compact": "workspace:^", "@biomejs/biome": "1.9.4", - "@types/node": "^18.18.6", + "@types/node": "^22.14.0", "ts-node": "^10.9.2", "typescript": "^5.2.2", "vitest": "^3.1.3" From 4d6a7ed2df4d07a74a59c335298c99c0045389dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 21 May 2025 22:38:17 -0400 Subject: [PATCH 110/282] Fixes some merge conflicts from most recent changes (#77) --- yarn.lock | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/yarn.lock b/yarn.lock index 1fb38804..39fc934e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -423,6 +423,19 @@ __metadata: languageName: unknown linkType: soft +"@openzeppelin-midnight/erc721@workspace:contracts/erc721": + version: 0.0.0-use.local + resolution: "@openzeppelin-midnight/erc721@workspace:contracts/erc721" + dependencies: + "@biomejs/biome": "npm:1.9.4" + "@openzeppelin-midnight/compact": "workspace:^" + "@types/node": "npm:^18.18.6" + ts-node: "npm:^10.9.2" + typescript: "npm:^5.2.2" + vitest: "npm:^3.1.3" + languageName: unknown + linkType: soft + "@openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" From c5077d9e3b2d3ca31cbf9ec6a3d291de56e5ecac Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 27 May 2025 18:01:36 -0400 Subject: [PATCH 111/282] Set private prop to true in package.json (#84) --- compact/package.json | 1 + contracts/utils/package.json | 1 + package.json | 3 +++ yarn.lock | 34 +++++++++++++++++----------------- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/compact/package.json b/compact/package.json index ac08934d..a32981e2 100644 --- a/compact/package.json +++ b/compact/package.json @@ -1,6 +1,7 @@ { "packageManager": "yarn@4.1.0", "name": "@openzeppelin-midnight/compact", + "private": true, "version": "0.0.1", "keywords": ["compact", "compiler"], "author": "", diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 8a4e7b55..89b3ead2 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -1,5 +1,6 @@ { "name": "@openzeppelin-midnight/utils", + "private": true, "type": "module", "main": "dist/index.js", "module": "dist/index.js", diff --git a/package.json b/package.json index f0e0753e..48feec6f 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,7 @@ { + "name": "openzeppelin-midnight", + "description": "Secure Smart Contract library for Midnight", + "private": true, "packageManager": "yarn@4.1.0", "workspaces": [ "compact/", diff --git a/yarn.lock b/yarn.lock index 39fc934e..5d61399d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1577,6 +1577,23 @@ __metadata: languageName: node linkType: hard +"openzeppelin-midnight@workspace:.": + version: 0.0.0-use.local + resolution: "openzeppelin-midnight@workspace:." + dependencies: + "@biomejs/biome": "npm:1.9.4" + "@midnight-ntwrk/compact-runtime": "npm:^0.8.1" + "@midnight-ntwrk/ledger": "npm:^4.0.0" + "@midnight-ntwrk/zswap": "npm:^4.0.0" + "@types/node": "npm:^22" + fast-check: "npm:^3.15.0" + ts-node: "npm:^10.9.2" + turbo: "npm:^2.5.1" + typescript: "npm:^5.2.2" + vitest: "npm:^3.1.3" + languageName: unknown + linkType: soft + "ora@npm:^8.2.0": version: 8.2.0 resolution: "ora@npm:8.2.0" @@ -1780,23 +1797,6 @@ __metadata: languageName: node linkType: hard -"root-workspace-0b6124@workspace:.": - version: 0.0.0-use.local - resolution: "root-workspace-0b6124@workspace:." - dependencies: - "@biomejs/biome": "npm:1.9.4" - "@midnight-ntwrk/compact-runtime": "npm:^0.8.1" - "@midnight-ntwrk/ledger": "npm:^4.0.0" - "@midnight-ntwrk/zswap": "npm:^4.0.0" - "@types/node": "npm:^22" - fast-check: "npm:^3.15.0" - ts-node: "npm:^10.9.2" - turbo: "npm:^2.5.1" - typescript: "npm:^5.2.2" - vitest: "npm:^3.1.3" - languageName: unknown - linkType: soft - "safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" From e8df634f09310b56621ada08d6816681b5ad1db8 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 27 May 2025 18:04:39 -0400 Subject: [PATCH 112/282] Set up antora and overview page (#83) --- docs/antora.yml | 8 + docs/modules/ROOT/nav.adoc | 1 + docs/modules/ROOT/pages/index.adoc | 90 +++++++++ docs/package.json | 15 ++ package.json | 5 +- turbo.json | 8 + yarn.lock | 299 ++++++++++++++++++++++++++++- 7 files changed, 424 insertions(+), 2 deletions(-) create mode 100644 docs/antora.yml create mode 100644 docs/modules/ROOT/nav.adoc create mode 100644 docs/modules/ROOT/pages/index.adoc create mode 100644 docs/package.json diff --git a/docs/antora.yml b/docs/antora.yml new file mode 100644 index 00000000..af185030 --- /dev/null +++ b/docs/antora.yml @@ -0,0 +1,8 @@ +name: contracts-midnight +title: Contracts for Midnight +version: 0.0.1 +nav: + - modules/ROOT/nav.adoc +asciidoc: + attributes: + page-sidebar-collapse-default: false diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc new file mode 100644 index 00000000..27f6f899 --- /dev/null +++ b/docs/modules/ROOT/nav.adoc @@ -0,0 +1 @@ +* xref:index.adoc[Overview] diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc new file mode 100644 index 00000000..5371e49a --- /dev/null +++ b/docs/modules/ROOT/pages/index.adoc @@ -0,0 +1,90 @@ +:midnight: https://midnight.network/[Midnight] +:nvm: https://github.com/nvm-sh/nvm[nvm] +:yarn: https://yarnpkg.com/getting-started/install[yarn] +:compact-installation: https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler[compact installation] + += Contracts for Midnight + +*A library for secure smart contract development* written in Compact for {midnight}. +This library consists of modules to build custom smart contracts. + +WARNING: This repo contains highly experimental code. Expect rapid iteration. *Use at your own risk.* + +== Installation + +Make sure you have {nvm} and {yarn} installed on your machine. + +Follow Midnight's {compact-installation} guide and confirm that `compactc` is in the `PATH` env variable. + +```bash +$ compactc + +Compactc version: 0.23.0 +Usage: compactc.bin ... + --help displays detailed usage information +``` + +=== Project setup + +Clone the repository: + +```bash +git clone git@github.com:OpenZeppelin/midnight-contracts.git +``` + +`cd` into it and then install dependencies and prepare the environment: + +```bash +nvm install && \ +yarn && \ +yarn prepare +``` + +== Usage + +Compile the contracts: + +```bash +$ npx turbo compact + +(...) +✔ [COMPILE] [1/2] Compiled ERC20.compact +@openzeppelin-midnight/erc20:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/erc20:compact: +✔ [COMPILE] [1/6] Compiled Initializable.compact +@openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/utils:compact: +✔ [COMPILE] [2/6] Compiled Pausable.compact +@openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/utils:compact: +✔ [COMPILE] [3/6] Compiled Utils.compact +@openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/utils:compact: +✔ [COMPILE] [4/6] Compiled test/mocks/MockInitializable.compact +@openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/utils:compact: Compiling 3 circuits: +✔ [COMPILE] [5/6] Compiled test/mocks/MockPausable.compact +@openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/utils:compact: Compiling 5 circuits: +✔ [COMPILE] [6/6] Compiled test/mocks/MockUtils.compact +@openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/utils:compact: + +✔ [COMPILE] [2/2] Compiled test/mocks/MockERC20.compact +@openzeppelin-midnight/erc20:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/erc20:compact: Compiling 15 circuits: + + + Tasks: 2 successful, 2 total +Cached: 0 cached, 2 total + Time: 7.178s +``` + +NOTE: Speed up the development process by skipping the prover and verifier key file generation: + +`npx turbo compact -- --skip-zk` + +Run tests: + +```bash +npx turbo test +``` diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 00000000..8999ad12 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,15 @@ +{ + "name": "docs", + "version": "0.0.1", + "scripts": { + "docs": "oz-docs -c .", + "docs:watch": "npm run docs watch", + "prepare-docs": "" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@openzeppelin/docs-utils": "^0.1.5" + } +} diff --git a/package.json b/package.json index 48feec6f..05ed18bf 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,13 @@ "packageManager": "yarn@4.1.0", "workspaces": [ "compact/", - "contracts/*/" + "contracts/*/", + "docs/" ], "scripts": { "prepare": "npx tsc -p ./compact && yarn rebuild", + "docs": "npx turbo run docs --filter=docs", + "docs:watch": "npx turbo run docs:watch --filter=docs", "compact": "turbo run compact", "build": "turbo run build", "test": "turbo run test", diff --git a/turbo.json b/turbo.json index 0940f33c..bab05a99 100644 --- a/turbo.json +++ b/turbo.json @@ -65,6 +65,14 @@ "clean": { "outputs": [], "cache": false + }, + "docs": { + "outputs": [], + "cache": false + }, + "docs:watch": { + "outputs": [], + "cache": false } } } diff --git a/yarn.lock b/yarn.lock index 5d61399d..52ce2668 100644 --- a/yarn.lock +++ b/yarn.lock @@ -280,6 +280,13 @@ __metadata: languageName: node linkType: hard +"@frangio/servbot@npm:^0.2.5": + version: 0.2.5 + resolution: "@frangio/servbot@npm:0.2.5" + checksum: 10/9c40bf898610efbbcc6529a5b4fe599d556aa7e74efa5591829f37be909b7aee4fe80660eb7dc04e1611547210d7ed65e29b0228a9a4271b30af54158e89ff88 + languageName: node + linkType: hard + "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -449,6 +456,25 @@ __metadata: languageName: unknown linkType: soft +"@openzeppelin/docs-utils@npm:^0.1.5": + version: 0.1.5 + resolution: "@openzeppelin/docs-utils@npm:0.1.5" + dependencies: + "@frangio/servbot": "npm:^0.2.5" + chalk: "npm:^3.0.0" + chokidar: "npm:^3.5.3" + env-paths: "npm:^2.2.0" + find-up: "npm:^4.1.0" + is-port-reachable: "npm:^3.0.0" + js-yaml: "npm:^3.13.1" + lodash.startcase: "npm:^4.4.0" + minimist: "npm:^1.2.0" + bin: + oz-docs: oz-docs.js + checksum: 10/08f1fc03f4d8e71e3000b501ea2536bdd065f44e5411c32ee1afc084e12075d4b65e5747556b60b63c57abe79718c292dad6c75cdb4fdf260d26570b7497eb58 + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -783,7 +809,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^4.0.0": +"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: @@ -799,6 +825,16 @@ __metadata: languageName: node linkType: hard +"anymatch@npm:~3.1.2": + version: 3.1.3 + resolution: "anymatch@npm:3.1.3" + dependencies: + normalize-path: "npm:^3.0.0" + picomatch: "npm:^2.0.4" + checksum: 10/3e044fd6d1d26545f235a9fe4d7a534e2029d8e59fa7fd9f2a6eb21230f6b5380ea1eaf55136e60cbf8e613544b3b766e7a6fa2102e2a3a117505466e3025dc2 + languageName: node + linkType: hard + "arg@npm:^4.1.0": version: 4.1.3 resolution: "arg@npm:4.1.3" @@ -806,6 +842,15 @@ __metadata: languageName: node linkType: hard +"argparse@npm:^1.0.7": + version: 1.0.10 + resolution: "argparse@npm:1.0.10" + dependencies: + sprintf-js: "npm:~1.0.2" + checksum: 10/c6a621343a553ff3779390bb5ee9c2263d6643ebcd7843227bdde6cc7adbed796eb5540ca98db19e3fd7b4714e1faa51551f8849b268bb62df27ddb15cbcd91e + languageName: node + linkType: hard + "assertion-error@npm:^2.0.1": version: 2.0.1 resolution: "assertion-error@npm:2.0.1" @@ -820,6 +865,13 @@ __metadata: languageName: node linkType: hard +"binary-extensions@npm:^2.0.0": + version: 2.3.0 + resolution: "binary-extensions@npm:2.3.0" + checksum: 10/bcad01494e8a9283abf18c1b967af65ee79b0c6a9e6fcfafebfe91dbe6e0fc7272bafb73389e198b310516ae04f7ad17d79aacf6cb4c0d5d5202a7e2e52c7d98 + languageName: node + linkType: hard + "brace-expansion@npm:^2.0.1": version: 2.0.1 resolution: "brace-expansion@npm:2.0.1" @@ -829,6 +881,15 @@ __metadata: languageName: node linkType: hard +"braces@npm:~3.0.2": + version: 3.0.3 + resolution: "braces@npm:3.0.3" + dependencies: + fill-range: "npm:^7.1.1" + checksum: 10/fad11a0d4697a27162840b02b1fad249c1683cbc510cd5bf1a471f2f8085c046d41094308c577a50a03a579dd99d5a6b3724c4b5e8b14df2c4443844cfcda2c6 + languageName: node + linkType: hard + "cac@npm:^6.7.14": version: 6.7.14 resolution: "cac@npm:6.7.14" @@ -869,6 +930,16 @@ __metadata: languageName: node linkType: hard +"chalk@npm:^3.0.0": + version: 3.0.0 + resolution: "chalk@npm:3.0.0" + dependencies: + ansi-styles: "npm:^4.1.0" + supports-color: "npm:^7.1.0" + checksum: 10/37f90b31fd655fb49c2bd8e2a68aebefddd64522655d001ef417e6f955def0ed9110a867ffc878a533f2dafea5f2032433a37c8a7614969baa7f8a1cd424ddfc + languageName: node + linkType: hard + "chalk@npm:^5.3.0, chalk@npm:^5.4.1": version: 5.4.1 resolution: "chalk@npm:5.4.1" @@ -883,6 +954,25 @@ __metadata: languageName: node linkType: hard +"chokidar@npm:^3.5.3": + version: 3.6.0 + resolution: "chokidar@npm:3.6.0" + dependencies: + anymatch: "npm:~3.1.2" + braces: "npm:~3.0.2" + fsevents: "npm:~2.3.2" + glob-parent: "npm:~5.1.2" + is-binary-path: "npm:~2.1.0" + is-glob: "npm:~4.0.1" + normalize-path: "npm:~3.0.0" + readdirp: "npm:~3.6.0" + dependenciesMeta: + fsevents: + optional: true + checksum: 10/c327fb07704443f8d15f7b4a7ce93b2f0bc0e6cea07ec28a7570aa22cd51fcf0379df589403976ea956c369f25aa82d84561947e227cd925902e1751371658df + languageName: node + linkType: hard + "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -966,6 +1056,14 @@ __metadata: languageName: node linkType: hard +"docs@workspace:docs": + version: 0.0.0-use.local + resolution: "docs@workspace:docs" + dependencies: + "@openzeppelin/docs-utils": "npm:^0.1.5" + languageName: unknown + linkType: soft + "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -1110,6 +1208,16 @@ __metadata: languageName: node linkType: hard +"esprima@npm:^4.0.0": + version: 4.0.1 + resolution: "esprima@npm:4.0.1" + bin: + esparse: ./bin/esparse.js + esvalidate: ./bin/esvalidate.js + checksum: 10/f1d3c622ad992421362294f7acf866aa9409fbad4eb2e8fa230bd33944ce371d32279667b242d8b8907ec2b6ad7353a717f3c0e60e748873a34a7905174bc0eb + languageName: node + linkType: hard + "estree-walker@npm:^3.0.3": version: 3.0.3 resolution: "estree-walker@npm:3.0.3" @@ -1154,6 +1262,25 @@ __metadata: languageName: node linkType: hard +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" + dependencies: + to-regex-range: "npm:^5.0.1" + checksum: 10/a7095cb39e5bc32fada2aa7c7249d3f6b01bd1ce461a61b0adabacccabd9198500c6fb1f68a7c851a657e273fce2233ba869638897f3d7ed2e87a2d89b4436ea + languageName: node + linkType: hard + +"find-up@npm:^4.1.0": + version: 4.1.0 + resolution: "find-up@npm:4.1.0" + dependencies: + locate-path: "npm:^5.0.0" + path-exists: "npm:^4.0.0" + checksum: 10/4c172680e8f8c1f78839486e14a43ef82e9decd0e74145f40707cc42e7420506d5ec92d9a11c22bd2c48fb0c384ea05dd30e10dd152fefeec6f2f75282a8b844 + languageName: node + linkType: hard + "foreground-child@npm:^3.1.0": version: 3.3.1 resolution: "foreground-child@npm:3.3.1" @@ -1199,6 +1326,15 @@ __metadata: languageName: node linkType: hard +"glob-parent@npm:~5.1.2": + version: 5.1.2 + resolution: "glob-parent@npm:5.1.2" + dependencies: + is-glob: "npm:^4.0.1" + checksum: 10/32cd106ce8c0d83731966d31517adb766d02c3812de49c30cfe0675c7c0ae6630c11214c54a5ae67aca882cf738d27fd7768f21aa19118b9245950554be07247 + languageName: node + linkType: hard + "glob@npm:^10.2.2": version: 10.4.5 resolution: "glob@npm:10.4.5" @@ -1222,6 +1358,13 @@ __metadata: languageName: node linkType: hard +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 10/261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.1.1": version: 4.2.0 resolution: "http-cache-semantics@npm:4.2.0" @@ -1275,6 +1418,22 @@ __metadata: languageName: node linkType: hard +"is-binary-path@npm:~2.1.0": + version: 2.1.0 + resolution: "is-binary-path@npm:2.1.0" + dependencies: + binary-extensions: "npm:^2.0.0" + checksum: 10/078e51b4f956c2c5fd2b26bb2672c3ccf7e1faff38e0ebdba45612265f4e3d9fc3127a1fa8370bbf09eab61339203c3d3b7af5662cbf8be4030f8fac37745b0e + languageName: node + linkType: hard + +"is-extglob@npm:^2.1.1": + version: 2.1.1 + resolution: "is-extglob@npm:2.1.1" + checksum: 10/df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 + languageName: node + linkType: hard + "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -1282,6 +1441,15 @@ __metadata: languageName: node linkType: hard +"is-glob@npm:^4.0.1, is-glob@npm:~4.0.1": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" + dependencies: + is-extglob: "npm:^2.1.1" + checksum: 10/3ed74f2b0cdf4f401f38edb0442ddfde3092d79d7d35c9919c86641efdbcbb32e45aa3c0f70ce5eecc946896cd5a0f26e4188b9f2b881876f7cb6c505b82da11 + languageName: node + linkType: hard + "is-interactive@npm:^2.0.0": version: 2.0.0 resolution: "is-interactive@npm:2.0.0" @@ -1289,6 +1457,20 @@ __metadata: languageName: node linkType: hard +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 10/6a6c3383f68afa1e05b286af866017c78f1226d43ac8cb064e115ff9ed85eb33f5c4f7216c96a71e4dfea289ef52c5da3aef5bbfade8ffe47a0465d70c0c8e86 + languageName: node + linkType: hard + +"is-port-reachable@npm:^3.0.0": + version: 3.1.0 + resolution: "is-port-reachable@npm:3.1.0" + checksum: 10/f6e51a1517acc8cc53f7ab08abe4f8f6262c680033a488b73700ab4986589a29b63db63bb1003110f54a7b555768501e32ab2aab138a082062a87694a18ee553 + languageName: node + linkType: hard + "is-unicode-supported@npm:^1.3.0": version: 1.3.0 resolution: "is-unicode-supported@npm:1.3.0" @@ -1330,6 +1512,18 @@ __metadata: languageName: node linkType: hard +"js-yaml@npm:^3.13.1": + version: 3.14.1 + resolution: "js-yaml@npm:3.14.1" + dependencies: + argparse: "npm:^1.0.7" + esprima: "npm:^4.0.0" + bin: + js-yaml: bin/js-yaml.js + checksum: 10/9e22d80b4d0105b9899135365f746d47466ed53ef4223c529b3c0f7a39907743fdbd3c4379f94f1106f02755b5e90b2faaf84801a891135544e1ea475d1a1379 + languageName: node + linkType: hard + "jsbn@npm:1.1.0": version: 1.1.0 resolution: "jsbn@npm:1.1.0" @@ -1337,6 +1531,22 @@ __metadata: languageName: node linkType: hard +"locate-path@npm:^5.0.0": + version: 5.0.0 + resolution: "locate-path@npm:5.0.0" + dependencies: + p-locate: "npm:^4.1.0" + checksum: 10/83e51725e67517287d73e1ded92b28602e3ae5580b301fe54bfb76c0c723e3f285b19252e375712316774cf52006cb236aed5704692c32db0d5d089b69696e30 + languageName: node + linkType: hard + +"lodash.startcase@npm:^4.4.0": + version: 4.4.0 + resolution: "lodash.startcase@npm:4.4.0" + checksum: 10/3091048a54a2f92bcf2c6441d2bd9a706fb133d5f461ae7c310d6dca1530338a06c91e9e42a5b14b12e875ddae1814d448050dc02afe2cec09b3995d8e836837 + languageName: node + linkType: hard + "log-symbols@npm:^6.0.0": version: 6.0.0 resolution: "log-symbols@npm:6.0.0" @@ -1422,6 +1632,13 @@ __metadata: languageName: node linkType: hard +"minimist@npm:^1.2.0": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 10/908491b6cc15a6c440ba5b22780a0ba89b9810e1aea684e253e43c4e3b8d56ec1dcdd7ea96dde119c29df59c936cde16062159eae4225c691e19c70b432b6e6f + languageName: node + linkType: hard + "minipass-collect@npm:^2.0.1": version: 2.0.1 resolution: "minipass-collect@npm:2.0.1" @@ -1561,6 +1778,13 @@ __metadata: languageName: node linkType: hard +"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": + version: 3.0.0 + resolution: "normalize-path@npm:3.0.0" + checksum: 10/88eeb4da891e10b1318c4b2476b6e2ecbeb5ff97d946815ffea7794c31a89017c70d7f34b3c2ebf23ef4e9fc9fb99f7dffe36da22011b5b5c6ffa34f4873ec20 + languageName: node + linkType: hard + "object-inspect@npm:^1.12.3": version: 1.13.4 resolution: "object-inspect@npm:1.13.4" @@ -1611,6 +1835,24 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^2.2.0": + version: 2.3.0 + resolution: "p-limit@npm:2.3.0" + dependencies: + p-try: "npm:^2.0.0" + checksum: 10/84ff17f1a38126c3314e91ecfe56aecbf36430940e2873dadaa773ffe072dc23b7af8e46d4b6485d302a11673fe94c6b67ca2cfbb60c989848b02100d0594ac1 + languageName: node + linkType: hard + +"p-locate@npm:^4.1.0": + version: 4.1.0 + resolution: "p-locate@npm:4.1.0" + dependencies: + p-limit: "npm:^2.2.0" + checksum: 10/513bd14a455f5da4ebfcb819ef706c54adb09097703de6aeaa5d26fe5ea16df92b48d1ac45e01e3944ce1e6aa2a66f7f8894742b8c9d6e276e16cd2049a2b870 + languageName: node + linkType: hard + "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" @@ -1618,6 +1860,13 @@ __metadata: languageName: node linkType: hard +"p-try@npm:^2.0.0": + version: 2.2.0 + resolution: "p-try@npm:2.2.0" + checksum: 10/f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae + languageName: node + linkType: hard + "package-json-from-dist@npm:^1.0.0": version: 1.0.1 resolution: "package-json-from-dist@npm:1.0.1" @@ -1625,6 +1874,13 @@ __metadata: languageName: node linkType: hard +"path-exists@npm:^4.0.0": + version: 4.0.0 + resolution: "path-exists@npm:4.0.0" + checksum: 10/505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 + languageName: node + linkType: hard + "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -1663,6 +1919,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 10/60c2595003b05e4535394d1da94850f5372c9427ca4413b71210f437f7b2ca091dbd611c45e8b37d10036fa8eade25c1b8951654f9d3973bfa66a2ff4d3b08bc + languageName: node + linkType: hard + "picomatch@npm:^4.0.2": version: 4.0.2 resolution: "picomatch@npm:4.0.2" @@ -1705,6 +1968,15 @@ __metadata: languageName: node linkType: hard +"readdirp@npm:~3.6.0": + version: 3.6.0 + resolution: "readdirp@npm:3.6.0" + dependencies: + picomatch: "npm:^2.2.1" + checksum: 10/196b30ef6ccf9b6e18c4e1724b7334f72a093d011a99f3b5920470f0b3406a51770867b3e1ae9711f227ef7a7065982f6ee2ce316746b2cb42c88efe44297fe7 + languageName: node + linkType: hard + "restore-cursor@npm:^5.0.0": version: 5.1.0 resolution: "restore-cursor@npm:5.1.0" @@ -1885,6 +2157,13 @@ __metadata: languageName: node linkType: hard +"sprintf-js@npm:~1.0.2": + version: 1.0.3 + resolution: "sprintf-js@npm:1.0.3" + checksum: 10/c34828732ab8509c2741e5fd1af6b767c3daf2c642f267788f933a65b1614943c282e74c4284f4fa749c264b18ee016a0d37a3e5b73aee446da46277d3a85daa + languageName: node + linkType: hard + "ssri@npm:^12.0.0": version: 12.0.0 resolution: "ssri@npm:12.0.0" @@ -1966,6 +2245,15 @@ __metadata: languageName: node linkType: hard +"supports-color@npm:^7.1.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 10/c8bb7afd564e3b26b50ca6ee47572c217526a1389fe018d00345856d4a9b08ffbd61fadaf283a87368d94c3dcdb8f5ffe2650a5a65863e21ad2730ca0f05210a + languageName: node + linkType: hard + "tar@npm:^7.4.3": version: 7.4.3 resolution: "tar@npm:7.4.3" @@ -2025,6 +2313,15 @@ __metadata: languageName: node linkType: hard +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: "npm:^7.0.0" + checksum: 10/10dda13571e1f5ad37546827e9b6d4252d2e0bc176c24a101252153ef435d83696e2557fe128c4678e4e78f5f01e83711c703eef9814eb12dab028580d45980a + languageName: node + linkType: hard + "ts-node@npm:^10.9.2": version: 10.9.2 resolution: "ts-node@npm:10.9.2" From 3f0920fa074a39dbc4af1f28c8679fdf39ec2403 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 27 May 2025 18:06:08 -0400 Subject: [PATCH 113/282] Improve readme (#80) --- README.md | 72 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 149a52b2..b3419bf9 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,21 @@ > Expect rapid iteration. > **Use at your own risk.** -## Development +## Installation -> ### Requirements -> -> - [node](https://nodejs.org/) -> - [yarn](https://yarnpkg.com/getting-started/install) -> - [compact](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) +Make sure you have [nvm](https://github.com/nvm-sh/nvm) and [yarn](https://yarnpkg.com/getting-started/install) installed on your machine. + +Follow Midnight's [compact installation guide](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) and confirm that `compactc` is in the `PATH` env variable. + +```bash +$ compactc + +Compactc version: 0.23.0 +Usage: compactc.bin ... + --help displays detailed usage information +``` + +## Set up the project Clone the repository: @@ -22,12 +30,58 @@ Clone the repository: git clone git@github.com:OpenZeppelin/midnight-contracts.git ``` -`cd` into it and then install dependencies, prepare compiler, and compile: +`cd` into it and then install dependencies and prepare the environment: ```bash +nvm install && \ yarn && \ -yarn run prepare && \ -npx turbo compact +yarn prepare +``` + +## Usage + +### Compile the contracts + +```bash +$ npx turbo compact + +(...) +✔ [COMPILE] [1/2] Compiled ERC20.compact +@openzeppelin-midnight/erc20:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/erc20:compact: +✔ [COMPILE] [1/6] Compiled Initializable.compact +@openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/utils:compact: +✔ [COMPILE] [2/6] Compiled Pausable.compact +@openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/utils:compact: +✔ [COMPILE] [3/6] Compiled Utils.compact +@openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/utils:compact: +✔ [COMPILE] [4/6] Compiled test/mocks/MockInitializable.compact +@openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/utils:compact: Compiling 3 circuits: +✔ [COMPILE] [5/6] Compiled test/mocks/MockPausable.compact +@openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/utils:compact: Compiling 5 circuits: +✔ [COMPILE] [6/6] Compiled test/mocks/MockUtils.compact +@openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/utils:compact: + +✔ [COMPILE] [2/2] Compiled test/mocks/MockERC20.compact +@openzeppelin-midnight/erc20:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/erc20:compact: Compiling 15 circuits: + + + Tasks: 2 successful, 2 total +Cached: 0 cached, 2 total + Time: 7.178s +``` + +**Note:** Speed up the development process by skipping the prover and verifier key file generation: + +```bash +npx turbo compact -- --skip-zk ``` ### Run tests From c8f8bda386de7020d45d1bbe06474aca36dbb79d Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Tue, 27 May 2025 18:24:45 -0400 Subject: [PATCH 114/282] Use burn_address function to generate 0 address --- contracts/utils/src/Utils.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index 686a644f..92f48a17 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -16,7 +16,7 @@ module Utils { * @return {Boolean} - Returns true if `keyOrAddress` is zero. */ export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { - const zero = pad(32, ""); + const zero = burn_address(); if (keyOrAddress.is_left) { return keyOrAddress == left(ZswapCoinPublicKey{ zero }); From c2e1c438f9d4e91907e8b42719da18b64af26677 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 28 May 2025 17:38:09 -0400 Subject: [PATCH 115/282] Fix JSDoc syntax --- contracts/utils/src/Utils.compact | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index 92f48a17..248786df 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -12,7 +12,7 @@ module Utils { /** * @description Returns whether `keyOrAddress` is the zero address. * - * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @param {Either} keyOrAddress - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @return {Boolean} - Returns true if `keyOrAddress` is zero. */ export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { @@ -29,8 +29,8 @@ module Utils { * @description Returns whether `keyOrAddress` is equal to `other`. Assumes that a ZswapCoinPublicKey * and a ContractAddress can never be equal * - * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. - * @param {other} - The other value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @param {Either} keyOrAddress - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @param {Either} other - The other value to check, either a ZswapCoinPublicKey or a ContractAddress. * @return {Boolean} - Returns true if `keyOrAddress` is is equal to `other`. */ export pure circuit isKeyOrAddressEqual( From 4dc110d59a7c14928837ebf1ae3dc898b1445d68 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 28 May 2025 19:25:30 -0400 Subject: [PATCH 116/282] Revert previous change --- contracts/utils/src/Utils.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index 248786df..1199cfd4 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -16,7 +16,7 @@ module Utils { * @return {Boolean} - Returns true if `keyOrAddress` is zero. */ export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { - const zero = burn_address(); + const zero = pad(32, ""); if (keyOrAddress.is_left) { return keyOrAddress == left(ZswapCoinPublicKey{ zero }); From 715e7a6fcb852d2b8448943b9f71ac69fcbc73c9 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 28 May 2025 19:36:36 -0400 Subject: [PATCH 117/282] Add isZeroKey utility function --- contracts/utils/src/Utils.compact | 11 +++++++++++ contracts/utils/src/test/mocks/MockUtils.compact | 4 ++++ contracts/utils/src/test/simulators/UtilsSimulator.ts | 9 +++++++++ contracts/utils/src/test/utils.test.ts | 10 ++++++++++ 4 files changed, 34 insertions(+) diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index 1199cfd4..dd544638 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -24,6 +24,17 @@ module Utils { return keyOrAddress == right(ContractAddress{ zero }); } } + + /** + * @description Returns whether `key` is the zero address. + * + * @param {ZswapCoinPublicKey} key - A ZswapCoinPublicKey + * @return {Boolean} - Returns true if `key` is zero. + */ + export pure circuit isKeyZero(key: ZswapCoinPublicKey): Boolean { + const zero = burn_address().left; + return zero == key; + } /** * @description Returns whether `keyOrAddress` is equal to `other`. Assumes that a ZswapCoinPublicKey diff --git a/contracts/utils/src/test/mocks/MockUtils.compact b/contracts/utils/src/test/mocks/MockUtils.compact index 152e74a1..1cc11f2f 100644 --- a/contracts/utils/src/test/mocks/MockUtils.compact +++ b/contracts/utils/src/test/mocks/MockUtils.compact @@ -16,3 +16,7 @@ export pure circuit isKeyOrAddressEqual( ): Boolean { return Utils_isKeyOrAddressEqual(keyOrAddress, other); } + +export pure circuit isKeyZero(key: ZswapCoinPublicKey): Boolean { + return Utils_isKeyZero(key); +} \ No newline at end of file diff --git a/contracts/utils/src/test/simulators/UtilsSimulator.ts b/contracts/utils/src/test/simulators/UtilsSimulator.ts index 6a618fa3..2647b5f4 100644 --- a/contracts/utils/src/test/simulators/UtilsSimulator.ts +++ b/contracts/utils/src/test/simulators/UtilsSimulator.ts @@ -115,4 +115,13 @@ export class UtilsSimulator other, ).result; } + + /** + * @description Returns whether `key` is the zero address. + * @param key The target value to check. + * @returns Returns true if `key` is zero. + */ + public isKeyZero(key: ZswapCoinPublicKey): boolean { + return this.contract.circuits.isKeyZero(this.circuitContext, key).result; + } } diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index f1ea12b2..f7acbd72 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -55,4 +55,14 @@ describe('Utils', () => { ).toBeFalsy(); }); }); + + describe('isKeyZero', () => { + it('should return zero for the zero address', () => { + expect(contract.isKeyZero(contractUtils.ZERO_KEY.left)).toBe(true); + }); + + it('should not return zero for nonzero addresses', () => { + expect(contract.isKeyZero(Z_SOME_KEY.left)).toBe(false); + }); + }); }); From 01d73c591a7d77bed24bf1ac701521fb4325076c Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 28 May 2025 23:27:05 -0400 Subject: [PATCH 118/282] Update witness file --- contracts/erc721/src/witnesses/ERC721Witnesses.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contracts/erc721/src/witnesses/ERC721Witnesses.ts b/contracts/erc721/src/witnesses/ERC721Witnesses.ts index da3c60e6..e3e7a723 100644 --- a/contracts/erc721/src/witnesses/ERC721Witnesses.ts +++ b/contracts/erc721/src/witnesses/ERC721Witnesses.ts @@ -1,3 +1,4 @@ +<<<<<<< HEAD import type * as Contract from "../artifacts/MockERC721/contract/index.cjs"; import type { WitnessContext } from "@midnight-ntwrk/compact-runtime"; @@ -23,3 +24,8 @@ export const ERC721Witnesses = { return [privateState, baseURI + privateState.tokenURI + tokenId.toString()]; }, }; +======= +// This is how we type an empty object. +export type ERC721PrivateState = Record; +export const ERC721Witnesses = {}; +>>>>>>> 84243c7 (Update witness file) From 074424c08b1f87bc98b017ad57f9db663d9b055c Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Thu, 29 May 2025 13:51:35 -0400 Subject: [PATCH 119/282] Improve readability --- contracts/utils/src/Utils.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index dd544638..75fcd6c9 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -32,7 +32,7 @@ module Utils { * @return {Boolean} - Returns true if `key` is zero. */ export pure circuit isKeyZero(key: ZswapCoinPublicKey): Boolean { - const zero = burn_address().left; + const zero = default; return zero == key; } From 2e04281cf4d94ce9b18d52f7f3cc8c3b20923f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 29 May 2025 13:52:32 -0400 Subject: [PATCH 120/282] Standardize Zero Address Structure (#90) --- contracts/utils/src/Utils.compact | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index 75fcd6c9..dac9bdf2 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -12,16 +12,17 @@ module Utils { /** * @description Returns whether `keyOrAddress` is the zero address. * - * @param {Either} keyOrAddress - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @notice Midnight's burn address is represented as left(default) + * in Compact, so we've chosen to represent the zero address as this structure as well. + * + * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @return {Boolean} - Returns true if `keyOrAddress` is zero. */ export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { - const zero = pad(32, ""); - if (keyOrAddress.is_left) { - return keyOrAddress == left(ZswapCoinPublicKey{ zero }); + return burn_address() == keyOrAddress; } else { - return keyOrAddress == right(ContractAddress{ zero }); + return right(default) == keyOrAddress; } } From 778c7b8a1c67caf7a2695ba52d0aa4ee63eef425 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 4 Jun 2025 13:53:09 -0400 Subject: [PATCH 121/282] Add isContractAddress utils function --- contracts/utils/src/Utils.compact | 10 ++++++++++ contracts/utils/src/test/mocks/MockUtils.compact | 4 ++++ contracts/utils/src/test/simulators/UtilsSimulator.ts | 9 +++++++++ contracts/utils/src/test/utils.test.ts | 10 ++++++++++ 4 files changed, 33 insertions(+) diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index dac9bdf2..802416a1 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -57,4 +57,14 @@ module Utils { return false; } } + + /** + * @description Returns whether `keyOrAddress` is a ContractAddress type + * + * @param {Either} keyOrAddress - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @return {Boolean} - Returns true if `keyOrAddress` is a ContractAddress + */ + export pure circuit isContractAddress(keyOrAddress: Either): Boolean { + return !keyOrAddress.is_left; + } } diff --git a/contracts/utils/src/test/mocks/MockUtils.compact b/contracts/utils/src/test/mocks/MockUtils.compact index 1cc11f2f..d42d4437 100644 --- a/contracts/utils/src/test/mocks/MockUtils.compact +++ b/contracts/utils/src/test/mocks/MockUtils.compact @@ -19,4 +19,8 @@ export pure circuit isKeyOrAddressEqual( export pure circuit isKeyZero(key: ZswapCoinPublicKey): Boolean { return Utils_isKeyZero(key); +} + +export pure circuit isContractAddress(keyOrAddress: Either): Boolean { + return Utils_isContractAddress(keyOrAddress); } \ No newline at end of file diff --git a/contracts/utils/src/test/simulators/UtilsSimulator.ts b/contracts/utils/src/test/simulators/UtilsSimulator.ts index 2647b5f4..9e173898 100644 --- a/contracts/utils/src/test/simulators/UtilsSimulator.ts +++ b/contracts/utils/src/test/simulators/UtilsSimulator.ts @@ -124,4 +124,13 @@ export class UtilsSimulator public isKeyZero(key: ZswapCoinPublicKey): boolean { return this.contract.circuits.isKeyZero(this.circuitContext, key).result; } + + /** + * @description Returns whether `keyOrAddress` is a ContractAddress type. + * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @returns Returns true if `keyOrAddress` is a ContractAddress + */ + public isContractAddress(keyOrAddress: Either): boolean { + return this.contract.circuits.isContractAddress(this.circuitContext, keyOrAddress).result; + } } diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index f7acbd72..41772fef 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -65,4 +65,14 @@ describe('Utils', () => { expect(contract.isKeyZero(Z_SOME_KEY.left)).toBe(false); }); }); + + describe('isContractAddress', () => { + it('should return true if ContractAddress', () => { + expect(contract.isContractAddress(SOME_CONTRACT)).toBe(true); + }); + + it('should return false ZswapCoinPublicKey', () => { + expect(contract.isContractAddress(Z_SOME_KEY)).toBe(false); + }); + }); }); From ec11c2f4ab55fcf8f296a1f72db946e5d1d85a94 Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Wed, 4 Jun 2025 15:09:57 -0400 Subject: [PATCH 122/282] fmt files --- contracts/utils/src/test/simulators/UtilsSimulator.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/contracts/utils/src/test/simulators/UtilsSimulator.ts b/contracts/utils/src/test/simulators/UtilsSimulator.ts index 9e173898..6b7618cb 100644 --- a/contracts/utils/src/test/simulators/UtilsSimulator.ts +++ b/contracts/utils/src/test/simulators/UtilsSimulator.ts @@ -130,7 +130,12 @@ export class UtilsSimulator * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @returns Returns true if `keyOrAddress` is a ContractAddress */ - public isContractAddress(keyOrAddress: Either): boolean { - return this.contract.circuits.isContractAddress(this.circuitContext, keyOrAddress).result; + public isContractAddress( + keyOrAddress: Either, + ): boolean { + return this.contract.circuits.isContractAddress( + this.circuitContext, + keyOrAddress, + ).result; } } From 505436cd33399ab2f31dcc54eebec2c243aefa8c Mon Sep 17 00:00:00 2001 From: Emanuel Solis Date: Fri, 6 Jun 2025 13:39:11 -0400 Subject: [PATCH 123/282] Create and test uninitialized mock contract --- .../mocks/MockUninitializedERC721.compact | 161 +++++ .../ERC721UninitializedSimulator.ts | 634 ++++++++++++++++++ 2 files changed, 795 insertions(+) create mode 100644 contracts/erc721/src/test/mocks/MockUninitializedERC721.compact create mode 100644 contracts/erc721/src/test/simulators/ERC721UninitializedSimulator.ts diff --git a/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact b/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact new file mode 100644 index 00000000..0b7c1fa7 --- /dev/null +++ b/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.15.0; + +import CompactStandardLibrary; + +import "../../ERC721" prefix ERC721_; + +export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; + +export circuit name(): Opaque<"string"> { + return ERC721_name(); +} + +export circuit symbol(): Opaque<"string"> { + return ERC721_symbol(); +} + +export circuit balanceOf(account: Either): Uint<128> { + return ERC721_balanceOf(account); +} + +export circuit ownerOf(tokenId: Uint<128>): Either { + return ERC721_ownerOf(tokenId); +} + +export circuit tokenURI(tokenId: Uint<128>): Opaque<"string"> { + return ERC721_tokenURI(tokenId); +} + +export circuit approve( + to: Either, + tokenId: Uint<128> +): [] { + return ERC721_approve(to, tokenId); +} + +export circuit getApproved(tokenId: Uint<128>): Either { + return ERC721_getApproved(tokenId); +} + +export circuit setApprovalForAll( + operator: Either, + approved: Boolean +): [] { + return ERC721_setApprovalForAll(operator, approved); +} + +export circuit isApprovedForAll( + owner: Either, + operator: Either +): Boolean { + return ERC721_isApprovedForAll(owner, operator); +} + +export circuit transferFrom( + from: Either, + to: Either, + tokenId: Uint<128> +): [] { + return ERC721_transferFrom(from, to, tokenId); +} + +export circuit _requireOwned(tokenId: Uint<128>): Either { + return ERC721__requireOwned(tokenId); +} + +export circuit _ownerOf(tokenId: Uint<128>): Either { + return ERC721__ownerOf(tokenId); +} + +export circuit _update( + to: Either, + tokenId: Uint<128>, + auth: Either +): Either { + return ERC721__update(to, tokenId, auth); +} + +export circuit _approve( + to: Either, + tokenId: Uint<128>, + auth: Either +): [] { + return ERC721__approve(to, tokenId, auth); +} + +export circuit _checkAuthorized( + owner: Either, + spender: Either, + tokenId: Uint<128> +): [] { + return ERC721__checkAuthorized(owner, spender, tokenId); +} + +export circuit _isAuthorized( + owner: Either, + spender: Either, + tokenId: Uint<128> +): Boolean { + return ERC721__isAuthorized(owner, spender, tokenId); +} + + +export circuit _getApproved(tokenId: Uint<128>): Either { + return ERC721__getApproved(tokenId); +} + +export circuit _setApprovalForAll( + owner: Either, + operator: Either, + approved: Boolean +): [] { + return ERC721__setApprovalForAll(owner, operator, approved); +} + +export circuit _mint( + to: Either, + tokenId: Uint<128> +): [] { + return ERC721__mint(to, tokenId); +} + +export circuit _burn(tokenId: Uint<128>): [] { + return ERC721__burn(tokenId); +} + +export circuit _transfer( + from: Either, + to: Either, + tokenId: Uint<128> +): [] { + return ERC721__transfer(from, to, tokenId); +} + +export circuit _setTokenURI(tokenId: Uint<128>, tokenURI: Opaque<"string">): [] { + return ERC721__setTokenURI(tokenId, tokenURI); +} + +export circuit _unsafeTransferFrom( + from: Either, + to: Either, + tokenId: Uint<128> +): [] { + return ERC721__unsafeTransferFrom(from, to, tokenId); +} + +export circuit _unsafe_transfer( + from: Either, + to: Either, + tokenId: Uint<128> +): [] { + return ERC721__unsafe_transfer(from, to, tokenId); +} + +export circuit _unsafe_mint( + to: Either, + tokenId: Uint<128> +): [] { + return ERC721__unsafe_mint(to, tokenId); +} \ No newline at end of file diff --git a/contracts/erc721/src/test/simulators/ERC721UninitializedSimulator.ts b/contracts/erc721/src/test/simulators/ERC721UninitializedSimulator.ts new file mode 100644 index 00000000..a89aa5df --- /dev/null +++ b/contracts/erc721/src/test/simulators/ERC721UninitializedSimulator.ts @@ -0,0 +1,634 @@ +import { + type CircuitContext, + type CoinPublicKey, + type ContractState, + QueryContext, + constructorContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import { sampleContractAddress } from '@midnight-ntwrk/zswap'; +import { + type Ledger, + type Either, + type ZswapCoinPublicKey, + type ContractAddress, + Contract as MockUninitializedERC721, + ledger, +} from '../../artifacts/MockUninitializedERC721/contract/index.cjs'; // Combined imports +import { + type ERC721PrivateState, + ERC721Witnesses, +} from '../../witnesses/ERC721Witnesses'; +import type { IContractSimulator } from '../types/test'; + +/** + * @description A simulator implementation of an ERC721 contract for testing purposes. + * @template P - The private state type, fixed to ERC721PrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class ERC721UninitializedSimulator + implements IContractSimulator +{ + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockUninitializedERC721; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor() { + this.contract = new MockUninitializedERC721( + ERC721Witnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type ERC721PrivateState. + */ + public getCurrentPrivateState(): ERC721PrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + + /** + * @description Returns the token name. + * @returns The token name. + */ + public name(): string { + return this.contract.impureCircuits.name(this.circuitContext).result; + } + + /** + * @description Returns the symbol of the token. + * @returns The token name. + */ + public symbol(): string { + return this.contract.impureCircuits.symbol(this.circuitContext).result; + } + + /** + * @description Returns the number of tokens in `account`'s account. + * @param account The public key to query. + * @return The number of tokens in `account`'s account. + */ + public balanceOf( + account: Either, + ): bigint { + return this.contract.impureCircuits.balanceOf(this.circuitContext, account) + .result; + } + + /** + * @description Returns the owner of the `tokenId` token. + * @param tokenId The identifier for a token. + * @return The public key that owns the token. + */ + public ownerOf(tokenId: bigint): Either { + return this.contract.impureCircuits.ownerOf(this.circuitContext, tokenId) + .result; + } + + /** + * @description Returns the token URI for the given `tokenId`. + * @notice Since Midnight does not support native strings and string operations + * within the Compact language, concatenating a base URI + token ID is not possible + * like in other NFT implementations. Therefore, we propose the URI storage + * approach; whereby, NFTs may or may not have unique "base" URIs. + * It's up to the implementation to decide on how to handle this. + * @param tokenId The identifier for a token. + * @returns The token id's URI. + */ + public tokenURI(tokenId: bigint): string { + return this.contract.impureCircuits.tokenURI(this.circuitContext, tokenId) + .result; + } + + /** + * @description Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * @param to The account receiving the approval + * @param tokenId The token `to` may be permitted to transfer + * @return None. + */ + public approve( + to: Either, + tokenId: bigint, + sender?: CoinPublicKey, + ) { + const res = this.contract.impureCircuits.approve( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + to, + tokenId, + ); + + this.circuitContext = res.context; + } + + /** + * @description Returns the account approved for `tokenId` token. + * @param tokenId The token an account may be approved to manage + * @return The account approved to manage the token + */ + public getApproved( + tokenId: bigint, + ): Either { + return this.contract.impureCircuits.getApproved( + this.circuitContext, + tokenId, + ).result; + } + + /** + * @description Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the address zero. + * + * @param operator An operator to manage the caller's tokens + * @param approved A boolean determining if `operator` may manage all tokens of the caller + * @return None. + */ + public setApprovalForAll( + operator: Either, + approved: boolean, + sender?: CoinPublicKey, + ) { + const res = this.contract.impureCircuits.setApprovalForAll( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + operator, + approved, + ); + + this.circuitContext = res.context; + } + + /** + * @description Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * @param owner The owner of a token + * @param operator An account that may operate on `owner`'s tokens + * @return A boolean determining if `operator` is allowed to manage all of the tokens of `owner` + */ + public isApprovedForAll( + owner: Either, + operator: Either, + ): boolean { + return this.contract.impureCircuits.isApprovedForAll( + this.circuitContext, + owner, + operator, + ).result; + } + + /** + * @description Transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * @param {Either} from - The source account from which the token is being transfered + * @param {Either} to - The target account to transfer token to + * @param {TokenId} tokenId - The token being transfered + * @return {[]} - None. + */ + public transferFrom( + from: Either, + to: Either, + tokenId: bigint, + sender?: CoinPublicKey, + ) { + const res = this.contract.impureCircuits.transferFrom( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + from, + to, + tokenId, + ); + + this.circuitContext = res.context; + } + + /** + * @description Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). + * Returns the owner. + * + * Overrides to ownership logic should be done to {_ownerOf}. + * + * @param tokenId The token that should be owned + * @return The owner of `tokenId` + */ + public _requireOwned( + tokenId: bigint, + ): Either { + return this.contract.impureCircuits._requireOwned( + this.circuitContext, + tokenId, + ).result; + } + + /** + * @description Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist + * + * @param tokenId The target token of the owner query + * @return The owner of the token + */ + public _ownerOf( + tokenId: bigint, + ): Either { + return this.contract.impureCircuits._ownerOf(this.circuitContext, tokenId) + .result; + } + + /** + * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner + * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. + * + * The `auth` argument is optional. If the value passed is non 0, then this function will check that + * `auth` is either the owner of the token, or approved to operate on the token (by the owner). + * + * @param to The intended recipient of the token transfer + * @param tokenId The token being transfered + * @param auth An account authorized to transfer the token + * @return Owner of the token before it was transfered + */ + public _update( + to: Either, + tokenId: bigint, + auth: Either, + ): Either { + const res = this.contract.impureCircuits._update( + this.circuitContext, + to, + tokenId, + auth, + ); + + this.circuitContext = res.context; + return res.result; + } + + /** + * @description Approve `to` to operate on `tokenId` + * + * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is + * either the owner of the token, or approved to operate on all tokens held by this owner. + * + * @param to The target account to approve + * @param tokenId The token to approve + * @param auth An account authorized to operate on all tokens held by the owner the token + * @return None. + */ + public _approve( + to: Either, + tokenId: bigint, + auth: Either, + ) { + this.circuitContext = this.contract.impureCircuits._approve( + this.circuitContext, + to, + tokenId, + auth, + ).context; + } + + /** + * @description Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. + * Reverts if: + * - `spender` does not have approval from `owner` for `tokenId`. + * - `spender` does not have approval to manage all of `owner`'s assets. + * + * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this + * assumption. + * + * @param owner Owner of the token + * @param spender Account operating on `tokenId` + * @param tokenId The token to spend + * @return None. + */ + public _checkAuthorized( + owner: Either, + spender: Either, + tokenId: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._checkAuthorized( + this.circuitContext, + owner, + spender, + tokenId, + ).context; + } + + /** + * @description Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in + * particular (ignoring whether it is owned by `owner`). + * + * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this + * assumption. + * + * @param owner Owner of the token + * @param spender Account that wishes to spend `tokenId` + * @param tokenId Token to spend + * @return A boolean determining if `spender` may manage `tokenId` + */ + public _isAuthorized( + owner: Either, + spender: Either, + tokenId: bigint, + ): boolean { + return this.contract.impureCircuits._isAuthorized( + this.circuitContext, + owner, + spender, + tokenId, + ).result; + } + + /** + * @description Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. + * + * @param tokenId The token to query + * @return An account approved to spend `tokenId` + */ + public _getApproved( + tokenId: bigint, + ): Either { + return this.contract.impureCircuits._getApproved( + this.circuitContext, + tokenId, + ).result; + } + + /** + * @description Approve `operator` to operate on all of `owner` tokens + * + * Requirements: + * - operator can't be the address zero. + * + * @param owner Owner of a token + * @param operator The account to approve + * @param approved A boolean determining if `operator` may operate on all of `owner` tokens + * @return None. + */ + public _setApprovalForAll( + owner: Either, + operator: Either, + approved: boolean, + ) { + this.circuitContext = this.contract.impureCircuits._setApprovalForAll( + this.circuitContext, + owner, + operator, + approved, + ).context; + } + + /** + * @description Mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * @param to The account receiving `tokenId` + * @param tokenId The token to transfer + * @return None. + */ + public _mint( + to: Either, + tokenId: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._mint( + this.circuitContext, + to, + tokenId, + ).context; + } + + /** + * @description Destroys `tokenId`. + * The approval is cleared when the token is burned. + * This is an internal function that does not check if the sender is authorized to operate on the token. + * + * Requirements: + * + * - `tokenId` must exist. + * + * @param tokenId The token to burn + * @return None. + */ + public _burn(tokenId: bigint) { + this.circuitContext = this.contract.impureCircuits._burn( + this.circuitContext, + tokenId, + ).context; + } + + /** + * @description Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on own_public_key(). + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * @param from The source account of the token transfer + * @param to The target account of the token transfer + * @param tokenId The token to transfer + * @return None. + */ + public _transfer( + from: Either, + to: Either, + tokenId: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._transfer( + this.circuitContext, + from, + to, + tokenId, + ).context; + } + + /** + * @description Sets the the URI as `tokenURI` for the given `tokenId`. + * The `tokenId` must exist. + * + * @notice The URI for a given NFT is usually set when the NFT is minted. + * + * @param tokenId The identifier of the token. + * @param tokenURI The URI of `tokenId`. + * @return None + */ + public _setTokenURI(tokenId: bigint, tokenURI: string) { + this.circuitContext = this.contract.impureCircuits._setTokenURI( + this.circuitContext, + tokenId, + tokenURI, + ).context; + } + + /** + * @description Transfers `tokenId` token from `from` to `to`. It does NOT check if the recipient is a ContractAddress. + * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the + * ContractAddress + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * @param {Either} from - The source account from which the token is being transfered + * @param {Either} to - The target account to transfer token to + * @param {TokenId} tokenId - The token being transfered + * @return {[]} - None. + */ + public _unsafeTransferFrom( + from: Either, + to: Either, + tokenId: bigint, + sender?: CoinPublicKey, + ) { + const res = this.contract.impureCircuits._unsafeTransferFrom( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + from, + to, + tokenId, + ); + + this.circuitContext = res.context; + } + + /** + * @description Transfers `tokenId` from `from` to `to`. + * As opposed to {_unsafeTransferFrom}, this imposes no restrictions on own_public_key(). + * It does NOT check if the recipient is a ContractAddress. + * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the + * ContractAddress + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * @param {Either} from - The source account of the token transfer + * @param {Either} to - The target account of the token transfer + * @param {TokenId} tokenId - The token to transfer + * @return {[]} - None. + */ + public _unsafe_transfer( + from: Either, + to: Either, + tokenId: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._unsafe_transfer( + this.circuitContext, + from, + to, + tokenId, + ).context; + } + + /** + * @description Mints `tokenId` and transfers it to `to`. It does NOT check if the recipient is a ContractAddress. + * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the + * ContractAddress + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * @param {Either} to - The account receiving `tokenId` + * @param {TokenId} tokenId - The token to transfer + * @return {[]} - None. + */ + public _unsafe_mint( + to: Either, + tokenId: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._unsafe_mint( + this.circuitContext, + to, + tokenId, + ).context; + } +} From b0a51f9adae33f97c77285c3916c66562484b43c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 11:10:36 -0400 Subject: [PATCH 124/282] Remove License from Mock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Fleming Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- contracts/erc721/src/test/mocks/MockUninitializedERC721.compact | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact b/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact index 0b7c1fa7..8b538877 100644 --- a/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact +++ b/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: MIT - pragma language_version >= 0.15.0; import CompactStandardLibrary; From 4025202496fbdbe9757229db90b23c6f6ec4742c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 11:13:40 -0400 Subject: [PATCH 125/282] fmt MockUninitializedERC721.compact MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Fleming Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- contracts/erc721/src/test/mocks/MockUninitializedERC721.compact | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact b/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact index 8b538877..907defe9 100644 --- a/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact +++ b/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact @@ -99,7 +99,6 @@ export circuit _isAuthorized( return ERC721__isAuthorized(owner, spender, tokenId); } - export circuit _getApproved(tokenId: Uint<128>): Either { return ERC721__getApproved(tokenId); } From 8774876fbc886d1e11aa151afba3e920171d939d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 11:23:22 -0400 Subject: [PATCH 126/282] Add formatting recommendations from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Fleming Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- contracts/erc721/src/test/mocks/MockUninitializedERC721.compact | 2 +- contracts/utils/src/test/mocks/MockUtils.compact | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact b/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact index 907defe9..d23ab436 100644 --- a/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact +++ b/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact @@ -155,4 +155,4 @@ export circuit _unsafe_mint( tokenId: Uint<128> ): [] { return ERC721__unsafe_mint(to, tokenId); -} \ No newline at end of file +} diff --git a/contracts/utils/src/test/mocks/MockUtils.compact b/contracts/utils/src/test/mocks/MockUtils.compact index d42d4437..71ad1606 100644 --- a/contracts/utils/src/test/mocks/MockUtils.compact +++ b/contracts/utils/src/test/mocks/MockUtils.compact @@ -23,4 +23,4 @@ export pure circuit isKeyZero(key: ZswapCoinPublicKey): Boolean { export pure circuit isContractAddress(keyOrAddress: Either): Boolean { return Utils_isContractAddress(keyOrAddress); -} \ No newline at end of file +} From c2a0f1609179411d660e3c5885f2a561fd6da0ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 5 Jun 2025 09:37:34 -0400 Subject: [PATCH 127/282] Update CODEOWNERS with OpenZeppelin team (#91) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7ef4cc84..292a22bb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -13,4 +13,4 @@ # Global: -* @andrew-fleming @emnul @0xisk +* @OpenZeppelin/contracts-midnight-maintainers From 2e1fd4e771019eb22b7bc44923224d511b0550b6 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 6 Jun 2025 13:02:01 -0400 Subject: [PATCH 128/282] Add extensibility section (#86) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Iskander <0xisk@proton.me> Co-authored-by: Iskander Co-authored-by: Emanuel Solis Co-authored-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- README.md | 6 + docs/modules/ROOT/nav.adoc | 1 + docs/modules/ROOT/pages/extensibility.adoc | 161 +++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 docs/modules/ROOT/pages/extensibility.adoc diff --git a/README.md b/README.md index b3419bf9..d2fd5a06 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,12 @@ Usage: compactc.bin ... ## Set up the project +> ### Requirements +> +> - [node](https://nodejs.org/) +> - [yarn](https://yarnpkg.com/getting-started/install) +> - [compact](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) + Clone the repository: ```bash diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 27f6f899..a6e49679 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -1 +1,2 @@ * xref:index.adoc[Overview] +* xref:extensibility.adoc[Extensibility] diff --git a/docs/modules/ROOT/pages/extensibility.adoc b/docs/modules/ROOT/pages/extensibility.adoc new file mode 100644 index 00000000..9633bb87 --- /dev/null +++ b/docs/modules/ROOT/pages/extensibility.adoc @@ -0,0 +1,161 @@ +# Extensibility + +## The Module/Contract Pattern + +We use the term *modular composition by delegation* to describe the practice of having contracts call into module-defined circuits to implement behavior. Rather than inheriting or overriding functionality, a contract delegates responsibility to the module by explicitly invoking its exported circuits. + +The idea is that there are two types of compact files: modules and contracts. To minimize risk, boilerplate, and avoid naming clashes, we follow these rules: + +### Modules + +Modules expose functionality through three circuit types: + +1. `internal`: private helpers → used to break up logic within the module. +2. `public`: composable building blocks → intended for contracts to use in complex flows (`_mint`, `_burn`). +3. `external`: standalone circuits → safe to expose as-is (`transfer`, `approve`). + +Modules must: + +- Export only `public` and `external` circuits. +- Prefix `public` circuits with `_` (e.g., `FungibleToken._mint`). +- Avoid `_` prefix for `external` circuits (e.g., `FungibleToken.transfer`). +- Avoid defining or calling constructors or `initialize()` directly. +- Optionally define an `initialize()` circuit for internal setup—but execution must be delegated to the contract. + +**Note**: Compact files must contain only one top-level module and all logic must be defined *inside* the module declaration. + +### Contracts + +Contracts compose behavior by explicitly invoking the relevant circuits from imported modules. Therefore, contracts: + +- Can import from modules. +- Should add prefix to imports (`import "FungibleToken" prefix FungibleToken_;`). +- Should re-expose external module circuits through wrapper circuits to control naming and layering. Avoid raw re-exports to prevent name clashes. +- Should implement constructor that calls `initialize` from imported modules. +- Must not call initializers outside of the constructor. + +This pattern balances modularity with local control, avoids tight coupling, and works within Compact’s language constraints. As Compact matures, this pattern will likely evolve as well. + +### Example contract implementing modules + +```ts +/** FungibleTokenMintablePausableOwnableContract */ +pragma language_version >= 0.15.0; + +import CompactStandardLibrary; + +import FungibleToken prefix FungibleToken_; +import Pausable prefix Pausable_; +import Ownable prefix Ownable_; + +constructor( + _name: Maybe>, + _symbol: Maybe>, + _decimals:Uint<8>, + _owner: Either +) { + FungibleToken_initialize(_name, _symbol, _decimals); + Ownable_initialize(_owner); +} + +/** IFungibleTokenMetadata */ + +export circuit name(): Opaque<"string"> { + return FungibleToken_name(); +} + +export circuit symbol(): Opaque<"string"> { + return FungibleToken_symbol(); +} + +export circuit decimals(): Uint<8> { + return FungibleToken_decimals(); +} + +/** IFungibleToken */ + +export circuit totalSupply(): Uint<128> { + return FungibleToken_totalSupply(); +} + +export circuit balanceOf( + account: Either +): Uint<128> { + return FungibleToken_balanceOf(account); +} + +export circuit allowance( + owner: Either, + spender: Either +): Uint<128> { + return FungibleToken_allowance(owner, spender); +} + +export circuit transfer( + to: Either, + value: Uint<128> +): Boolean { + Pausable_assertNotPaused(); + return FungibleToken_transfer(to, value); +} + +export circuit transferFrom( + from: Either, + to: Either, + value: Uint<128> +): Boolean { + Pausable_assertNotPaused(); + return FungibleToken_transferFrom(from, to, value); +} + +export circuit approve( + spender: Either, + value: Uint<128> +): Boolean { + Pausable_assertNotPaused(); + return FungibleToken_approve(spender, value); +} + +/** IMintable */ + +export circuit mint( + account: Either, + value: Uint<128> +): [] { + Pausable_assertNotPaused(); + Ownable_assertOnlyOwner(); + return FungibleToken__mint(account, value); +} + +/** IPausable */ + +export circuit isPaused(): Boolean { + return Pausable_isPaused(); +} + +export circuit pause(): [] { + Ownable_assertOnlyOwner(); + return Pausable__pause(); +} + +export circuit unpause(): [] { + Ownable_assertOnlyOwner(); + return Pausable__unpause(); +} + +/** IOwnable */ + +export circuit owner(): Either { + return Ownable_owner(); +} + +export circuit transferOwnership( + newOwner: Either +): [] { + return Ownable_transferOwnership(newOwner); +} + +export circuit renounceOwnership(): [] { + return Ownable_renounceOwnership(); +} +``` \ No newline at end of file From d42f19f4fdd48864b1cacedd071466e6929e843b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:41:39 -0400 Subject: [PATCH 129/282] fmt biome.json --- biome.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biome.json b/biome.json index 8bf55b0a..a9bc3f3a 100644 --- a/biome.json +++ b/biome.json @@ -24,7 +24,7 @@ "organizeImports": { "enabled": true }, -"linter": { + "linter": { "enabled": true, "rules": { "recommended": true, From 06e7b67e5633b45a2d4fcd716eca407a3943f8a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:42:04 -0400 Subject: [PATCH 130/282] Fix issue with formatting files in project root --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 05ed18bf..c0789e2a 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "test": "turbo run test", "fmt": "turbo run fmt", "fmt:fix": "turbo run fmt:fix", + "fmt:rootDir": "biome format . --write", "lint": "turbo run lint", "lint:fix": "turbo run lint:fix", "types": "turbo run types", From 033a625d9b42da48f4f8967f45d9902a0d3e308c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:44:49 -0400 Subject: [PATCH 131/282] Fix redundant compact turbo task calls --- contracts/erc20/turbo.json | 9 +++++++++ contracts/erc721/turbo.json | 9 +++++++++ contracts/utils/turbo.json | 9 +++++++++ turbo.json | 31 +++++++------------------------ 4 files changed, 34 insertions(+), 24 deletions(-) create mode 100644 contracts/erc20/turbo.json create mode 100644 contracts/erc721/turbo.json create mode 100644 contracts/utils/turbo.json diff --git a/contracts/erc20/turbo.json b/contracts/erc20/turbo.json new file mode 100644 index 00000000..5a61a218 --- /dev/null +++ b/contracts/erc20/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "tasks": { + "build": { + "dependsOn": ["^build", "compact"] + } + } +} diff --git a/contracts/erc721/turbo.json b/contracts/erc721/turbo.json new file mode 100644 index 00000000..5a61a218 --- /dev/null +++ b/contracts/erc721/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "tasks": { + "build": { + "dependsOn": ["^build", "compact"] + } + } +} diff --git a/contracts/utils/turbo.json b/contracts/utils/turbo.json new file mode 100644 index 00000000..5a61a218 --- /dev/null +++ b/contracts/utils/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "tasks": { + "build": { + "dependsOn": ["^build", "compact"] + } + } +} diff --git a/turbo.json b/turbo.json index bab05a99..630131f6 100644 --- a/turbo.json +++ b/turbo.json @@ -2,31 +2,18 @@ "$schema": "https://turbo.build/schema.json", "tasks": { "compact": { - "env": [ - "COMPACT_HOME" - ], - "inputs": [ - "src/**/*.compact" - ], + "env": ["COMPACT_HOME"], + "inputs": ["src/**/*.compact"], "outputLogs": "new-only", - "outputs": [ - "src/artifacts/**", - "src/gen/**", - "gen/**" - ] + "outputs": ["src/artifacts/**", "src/gen/**", "gen/**"] }, "test": { "outputs": [], "cache": false }, "build": { - "dependsOn": [ - "^build", - "compact" - ], - "env": [ - "COMPACT_HOME" - ], + "dependsOn": ["^build"], + "env": ["COMPACT_HOME"], "inputs": [ "src/**/*.ts", "!src/**/*.test.ts", @@ -35,16 +22,12 @@ "tsconfig.build.json", ".env" ], - "outputs": [ - "dist/**" - ] + "outputs": ["dist/**"] }, "types": { "outputs": [], "cache": false, - "dependsOn": [ - "compact" - ] + "dependsOn": ["compact"] }, "fmt": { "outputs": [], From 1fa5bd1a92cda6ee841d69b389612232c195016e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:45:08 -0400 Subject: [PATCH 132/282] Adds build step to compact workspace --- compact/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/compact/package.json b/compact/package.json index a32981e2..7694d2ac 100644 --- a/compact/package.json +++ b/compact/package.json @@ -17,6 +17,7 @@ "compact-compiler": "dist/runCompiler.js" }, "scripts": { + "build": "tsc -p .", "types": "tsc -p tsconfig.json --noEmit", "fmt": "biome format", "fmt:fix": "biome format --write", From 5a2ea43cf13bfb122a007d847150351345a75bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:45:23 -0400 Subject: [PATCH 133/282] Updates turbo.json --- compact/turbo.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compact/turbo.json b/compact/turbo.json index 9c9378a1..7e7bb2c7 100644 --- a/compact/turbo.json +++ b/compact/turbo.json @@ -3,10 +3,10 @@ "extends": ["//"], "tasks": { "build": { - "outputs": ["compactc/**"], + "outputs": ["dist/**"], + "inputs": ["src/**/*.ts", "tsconfig.json"], "env": ["COMPACT_HOME"], - "inputs": ["src/**.cjs"], "cache": true } } -} +} \ No newline at end of file From a0a6c2bbaade4ee29e0af4f7ec55b26568bb9d3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:45:42 -0400 Subject: [PATCH 134/282] fmt package.json --- docs/package.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/package.json b/docs/package.json index 8999ad12..02410b35 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,15 +1,15 @@ { - "name": "docs", - "version": "0.0.1", - "scripts": { - "docs": "oz-docs -c .", - "docs:watch": "npm run docs watch", - "prepare-docs": "" - }, - "keywords": [], - "author": "", - "license": "ISC", - "devDependencies": { - "@openzeppelin/docs-utils": "^0.1.5" - } + "name": "docs", + "version": "0.0.1", + "scripts": { + "docs": "oz-docs -c .", + "docs:watch": "npm run docs watch", + "prepare-docs": "" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@openzeppelin/docs-utils": "^0.1.5" + } } From 36182fd632c93abc0e4793d6b5a965c58f8ed0a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:45:52 -0400 Subject: [PATCH 135/282] Remove old file --- compact/.eslintrc.cjs | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 compact/.eslintrc.cjs diff --git a/compact/.eslintrc.cjs b/compact/.eslintrc.cjs deleted file mode 100644 index 32fa19b8..00000000 --- a/compact/.eslintrc.cjs +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - node: true, - jest: true, - }, - extends: [ - 'plugin:prettier/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - overrides: [], - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['tsconfig.json'], - }, - rules: { - '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 - '@typescript-eslint/no-floating-promises': 'warn', - '@typescript-eslint/promise-function-async': 'off', - '@typescript-eslint/no-redeclare': 'off', - }, -}; From 5711f2ad02144de02e3b410e74aab0c117c5dec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 22:23:49 -0400 Subject: [PATCH 136/282] Configure composite action --- .github/actions/setup/action.yml | 101 +++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 .github/actions/setup/action.yml diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml new file mode 100644 index 00000000..87581a97 --- /dev/null +++ b/.github/actions/setup/action.yml @@ -0,0 +1,101 @@ +name: 'Setup Environment' +description: 'Sets up the environment with Compact compiler, yarn, and Node.js' +timeout-minutes: 15 +env: + COMPACT_HOME: $HOME/compactc + PATH: $HOME/compactc:$PATH + +inputs: + skip-compile: + description: 'Skip the fast compile step' + required: false + default: 'false' + +runs: + using: "composite" + steps: + - name: Check out code + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Recommended by turbo team + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v4 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Cache turbo build setup + uses: actions/cache@v4 + with: + path: .turbo + key: ${{ runner.os }}-turbo-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-turbo- + + - name: Cache Compact compiler + uses: actions/cache@v4 + id: cache-compact + with: + path: ${{ env.COMPACT_HOME }} + key: compact-compiler-0.23.0 + restore-keys: | + compact-compiler- + + - name: Install Compact compiler + if: steps.cache-compact.outputs.cache-hit != 'true' + id: setup + shell: bash + run: | + COMPILER_VERSION="0.23.0" + LANGUAGE_VERSION="0.15.0" + mkdir -p "${{ env.COMPACT_HOME }}" + + echo "⬇️ Downloading Compact compiler..." + cd "${{ env.COMPACT_HOME }}" + curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip + unzip compactc.zip + chmod +x compactc.bin zkir compactc + + # Test installation + "${{ env.COMPACT_HOME }}/compactc" --version + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + + - name: Install dependencies + shell: bash + run: yarn install --immutable + + - name: Build compact package + shell: bash + run: | + yarn build -- --filter=compact/ + + - name: Validate build artifacts + shell: bash + run: | + REQUIRED_FILES=( + "packages/compact/dist/runCompiler.js" + "packages/compact/dist/runBuilder.js" + ) + for file in "${REQUIRED_FILES[@]}"; do + if [ ! -f "$file" ]; then + echo "::error::❌ Missing required file: $file" + exit 1 + fi + done + + - name: Fast compile contracts (skip zk) + if: ${{ inputs.skip-compile != 'true' }} + shell: bash + run: yarn compact -- --skip-zk \ No newline at end of file From 83ff44dc81f25b050e0f837edd383c927142cde1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 22:24:24 -0400 Subject: [PATCH 137/282] Configure workflow to check for lints and formatting --- .github/workflows/checks.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/checks.yml diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 00000000..0e3f6279 --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,34 @@ +name: Checks + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: checks-${{ github.run_id }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + checks: + name: Run Checks + runs-on: ubuntu-22.04 + + steps: + - name: Setup Environment + uses: ./.github/actions/setup + + - name: Lint + run: yarn lint + timeout-minutes: 10 + + - name: Format + run: yarn fmt + timeout-minutes: 10 + + - name: Cleanup on failure + if: failure() + run: | + echo "Checks failed. Cleaning up..." + rm -rf contracts/*/src/artifacts/ \ No newline at end of file From 3a458d8ff98d52250a0bba17677fd3b5ec39652b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 22:24:34 -0400 Subject: [PATCH 138/282] Configure CodeQL workflow --- .github/workflows/codeql.yml | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..e85b7f49 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,45 @@ +name: "CodeQL Analysis" + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-22.04 + if: github.event.repository.private == false + timeout-minutes: 30 + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: ["javascript", "typescript"] + + steps: + - name: Setup Environment + uses: ./.github/actions/setup + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # We can add custom queries later when needed + # queries: security-extended + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{ matrix.language }}" + + - name: Cleanup on failure + if: failure() + run: | + echo "Analysis failed. Cleaning up..." + rm -rf contracts/*/src/artifacts/ \ No newline at end of file From 6e6a63f7348b218d062e3ddb4a9c8bb3c931dc9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 22:25:06 -0400 Subject: [PATCH 139/282] Configure workflow to test compact compiler install --- .github/workflows/compact-compiler.yml | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/compact-compiler.yml diff --git a/.github/workflows/compact-compiler.yml b/.github/workflows/compact-compiler.yml new file mode 100644 index 00000000..38a96e56 --- /dev/null +++ b/.github/workflows/compact-compiler.yml @@ -0,0 +1,43 @@ +name: Install Compact Compiler + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + COMPACT_HOME: $HOME/compactc + +jobs: + install: + name: Install Compact Compiler + runs-on: ubuntu-22.04 + + steps: + - name: Cache Compact compiler + uses: actions/cache@v4 + id: cache-compact + with: + path: ${{ env.COMPACT_HOME }} + key: compact-compiler-0.23.0 + restore-keys: | + compact-compiler- + + - name: Install Compact compiler + if: steps.cache-compact.outputs.cache-hit != 'true' + id: setup + shell: bash + run: | + COMPILER_VERSION="0.23.0" + LANGUAGE_VERSION="0.15.0" + mkdir -p "${{ env.COMPACT_HOME }}" + + echo "⬇️ Downloading Compact compiler..." + cd "${{ env.COMPACT_HOME }}" + curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip + unzip compactc.zip + chmod +x compactc.bin zkir compactc + + # Test installation + "${{ env.COMPACT_HOME }}/compactc" --version \ No newline at end of file From 91e25fd8e17789814be9fc0ca75a41722a542f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 23:04:57 -0400 Subject: [PATCH 140/282] Add skip-compile input --- .github/workflows/checks.yml | 2 ++ .github/workflows/codeql.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 0e3f6279..0d050ec7 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -18,6 +18,8 @@ jobs: steps: - name: Setup Environment uses: ./.github/actions/setup + with: + skip-compile: 'true' - name: Lint run: yarn lint diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index e85b7f49..3e3e5069 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -25,6 +25,8 @@ jobs: steps: - name: Setup Environment uses: ./.github/actions/setup + with: + skip-compile: 'true' - name: Initialize CodeQL uses: github/codeql-action/init@v3 From dcbc249986a75e68a01a668382d0fea5e18bff32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 23:42:27 -0400 Subject: [PATCH 141/282] Add contracts build workflow --- .github/workflows/contracts-build.yml | 55 +++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 .github/workflows/contracts-build.yml diff --git a/.github/workflows/contracts-build.yml b/.github/workflows/contracts-build.yml new file mode 100644 index 00000000..ff025208 --- /dev/null +++ b/.github/workflows/contracts-build.yml @@ -0,0 +1,55 @@ +name: Contracts Build + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: contracts-build-${{ github.run_id }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build Compact Contracts + runs-on: ubuntu-22.04 + + steps: + - name: Setup Environment + uses: ./.github/actions/setup + + - name: Build contracts + run: yarn build + timeout-minutes: 10 + + - name: Check if build artifacts exist + run: | + if ! find contracts -type d -name artifacts | grep -q . && [ ! -d "packages/compact/dist" ]; then + echo "::error::❌ Build artifacts not found in any contracts/*/artifacts or in packages/compact/dist!" + exit 1 + fi + + # List build artifacts + echo "✅ Build artifacts found:" + echo "Package build artifacts (dist):" + find contracts -name "dist" -type d -exec ls -la {} \; + echo -e "\nCompact code artifacts (src/artifacts):" + find contracts -name "artifacts" -type d -exec ls -la {} \; + + - name: Upload build artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: compact-builds + path: | + contracts/*/dist/ + contracts/*/src/artifacts/ + retention-days: 7 + + - name: Cleanup on failure + if: failure() + run: | + echo "Build failed. Cleaning up..." + rm -rf contracts/*/dist/ + rm -rf contracts/*/src/artifacts/ \ No newline at end of file From c321c56e8a94b507430e9e711edc33933ea1df42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 23:42:46 -0400 Subject: [PATCH 142/282] Add contracts compile workflow --- .github/workflows/contracts-compile.yml | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/contracts-compile.yml diff --git a/.github/workflows/contracts-compile.yml b/.github/workflows/contracts-compile.yml new file mode 100644 index 00000000..3b550dc0 --- /dev/null +++ b/.github/workflows/contracts-compile.yml @@ -0,0 +1,34 @@ +name: Contracts Compile + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + checks: write + actions: write + contents: read + +concurrency: + group: contracts-compile-${{ github.run_id }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + compile: + name: Fast Compile Contracts + runs-on: ubuntu-22.04 + timeout-minutes: 15 + + steps: + - name: Setup Environment + uses: ./.github/actions/setup + with: + skip-compile: 'true' + + - name: Cleanup on failure + if: failure() + run: | + echo "Compilation failed. Cleaning up..." + rm -rf contracts/*/src/artifacts/ \ No newline at end of file From 2bdd1b0b2a136196dd4f079142e23def02ed5fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 23:43:09 -0400 Subject: [PATCH 143/282] Add contracts test workflow --- .github/workflows/contracts-test.yml | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/contracts-test.yml diff --git a/.github/workflows/contracts-test.yml b/.github/workflows/contracts-test.yml new file mode 100644 index 00000000..299f305d --- /dev/null +++ b/.github/workflows/contracts-test.yml @@ -0,0 +1,42 @@ +name: Contracts Test + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: contracts-test-${{ github.run_id }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: Test Contracts + runs-on: ubuntu-22.04 + + steps: + - name: Setup Environment + uses: ./.github/actions/setup + with: + skip-compile: 'true' + + - name: Verify Compact build artifacts + run: | + if ! find contracts/*/src/artifacts -type d 2>/dev/null | grep -q .; then + echo "::error::❌ Compact build artifacts not found!" + exit 1 + fi + echo "✅ Compact build artifacts found" + + - name: Run contract tests + run: yarn test + timeout-minutes: 15 + + - name: Cleanup on failure + if: failure() + run: | + echo "Tests failed. Cleaning up..." + rm -rf contracts/*/dist/ + rm -rf contracts/*/src/artifacts/ + \ No newline at end of file From 3f3fecee66d6332228f9a0b92c88ee55d7856bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 23:43:27 -0400 Subject: [PATCH 144/282] Refator workflows --- .github/actions/setup/action.yml | 46 ++--------- .github/workflows/checks.yml | 5 ++ .github/workflows/codeql.yml | 5 ++ .github/workflows/contracts-build.yml | 46 ++++++++--- .github/workflows/contracts-compile.yml | 36 ++++++++- .github/workflows/contracts-test.yml | 42 +++++++++- .github/workflows/contracts-version.yml | 81 +++++++++++++++++++ ...pact-compiler.yml => install-compiler.yml} | 30 +++---- compact/package.json | 2 +- compact/turbo.json | 2 +- contracts/utils/package.json | 4 +- package.json | 1 + 12 files changed, 228 insertions(+), 72 deletions(-) create mode 100644 .github/workflows/contracts-version.yml rename .github/workflows/{compact-compiler.yml => install-compiler.yml} (58%) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 87581a97..37c6e7bc 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -1,9 +1,6 @@ name: 'Setup Environment' description: 'Sets up the environment with Compact compiler, yarn, and Node.js' timeout-minutes: 15 -env: - COMPACT_HOME: $HOME/compactc - PATH: $HOME/compactc:$PATH inputs: skip-compile: @@ -14,12 +11,8 @@ inputs: runs: using: "composite" steps: - - name: Check out code - uses: actions/checkout@v4 - with: - fetch-depth: 2 # Recommended by turbo team - - name: Get yarn cache directory path + shell: bash id: yarn-cache-dir-path run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT @@ -38,33 +31,6 @@ runs: key: ${{ runner.os }}-turbo-${{ github.sha }} restore-keys: | ${{ runner.os }}-turbo- - - - name: Cache Compact compiler - uses: actions/cache@v4 - id: cache-compact - with: - path: ${{ env.COMPACT_HOME }} - key: compact-compiler-0.23.0 - restore-keys: | - compact-compiler- - - - name: Install Compact compiler - if: steps.cache-compact.outputs.cache-hit != 'true' - id: setup - shell: bash - run: | - COMPILER_VERSION="0.23.0" - LANGUAGE_VERSION="0.15.0" - mkdir -p "${{ env.COMPACT_HOME }}" - - echo "⬇️ Downloading Compact compiler..." - cd "${{ env.COMPACT_HOME }}" - curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip - unzip compactc.zip - chmod +x compactc.bin zkir compactc - - # Test installation - "${{ env.COMPACT_HOME }}/compactc" --version - name: Setup Node.js uses: actions/setup-node@v4 @@ -78,15 +44,17 @@ runs: - name: Build compact package shell: bash + env: + TURBO_TELEMETRY_DISABLED: 1 run: | - yarn build -- --filter=compact/ + yarn build:compact - name: Validate build artifacts shell: bash run: | REQUIRED_FILES=( - "packages/compact/dist/runCompiler.js" - "packages/compact/dist/runBuilder.js" + "compact/dist/runCompiler.js" + "compact/dist/runBuilder.js" ) for file in "${REQUIRED_FILES[@]}"; do if [ ! -f "$file" ]; then @@ -96,6 +64,8 @@ runs: done - name: Fast compile contracts (skip zk) + env: + TURBO_TELEMETRY_DISABLED: 1 if: ${{ inputs.skip-compile != 'true' }} shell: bash run: yarn compact -- --skip-zk \ No newline at end of file diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 0d050ec7..07eca398 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -16,6 +16,11 @@ jobs: runs-on: ubuntu-22.04 steps: + - name: Check out code + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Recommended by turbo team + - name: Setup Environment uses: ./.github/actions/setup with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3e3e5069..9470a1ce 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -23,6 +23,11 @@ jobs: language: ["javascript", "typescript"] steps: + - name: Check out code + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Recommended by turbo team + - name: Setup Environment uses: ./.github/actions/setup with: diff --git a/.github/workflows/contracts-build.yml b/.github/workflows/contracts-build.yml index ff025208..218a2978 100644 --- a/.github/workflows/contracts-build.yml +++ b/.github/workflows/contracts-build.yml @@ -16,8 +16,44 @@ jobs: runs-on: ubuntu-22.04 steps: + - name: Check out code + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Recommended by turbo team + - name: Setup Environment uses: ./.github/actions/setup + with: + skip-compile: 'true' + + - name: Install Compact compiler + id: setup + shell: bash + run: | + # Set version variables + COMPILER_VERSION="0.23.0" + LANGUAGE_VERSION="0.15.0" + + # Create directory for compiler + COMPACT_HOME="$HOME/compactc" + mkdir -p "$COMPACT_HOME" + cd "$COMPACT_HOME" + + echo "⬇️ Downloading Compact compiler..." + cd "$COMPACT_HOME" + curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip + unzip compactc.zip + chmod +x compactc.bin zkir compactc + + # Verify installation + [ -f "$COMPACT_HOME/compactc" ] || { echo "::error::❌ Failed to install compiler - compactc not found"; exit 1; } + + # Test installation + "$COMPACT_HOME/compactc" --version + + # Set up environment variables + echo "COMPACT_HOME=$COMPACT_HOME" >> $GITHUB_ENV + echo "$COMPACT_HOME" >> $GITHUB_PATH - name: Build contracts run: yarn build @@ -37,16 +73,6 @@ jobs: echo -e "\nCompact code artifacts (src/artifacts):" find contracts -name "artifacts" -type d -exec ls -la {} \; - - name: Upload build artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: compact-builds - path: | - contracts/*/dist/ - contracts/*/src/artifacts/ - retention-days: 7 - - name: Cleanup on failure if: failure() run: | diff --git a/.github/workflows/contracts-compile.yml b/.github/workflows/contracts-compile.yml index 3b550dc0..b3a2b8c9 100644 --- a/.github/workflows/contracts-compile.yml +++ b/.github/workflows/contracts-compile.yml @@ -22,10 +22,42 @@ jobs: timeout-minutes: 15 steps: + - name: Check out code + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Recommended by turbo team + + - name: Install Compact compiler + id: setup + shell: bash + run: | + # Set version variables + COMPILER_VERSION="0.23.0" + LANGUAGE_VERSION="0.15.0" + + # Create directory for compiler + COMPACT_HOME="$HOME/compactc" + mkdir -p "$COMPACT_HOME" + cd "$COMPACT_HOME" + + echo "⬇️ Downloading Compact compiler..." + cd "$COMPACT_HOME" + curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip + unzip compactc.zip + chmod +x compactc.bin zkir compactc + + # Verify installation + [ -f "$COMPACT_HOME/compactc" ] || { echo "::error::❌ Failed to install compiler - compactc not found"; exit 1; } + + # Test installation + "$COMPACT_HOME/compactc" --version + + # Set up environment variables + echo "COMPACT_HOME=$COMPACT_HOME" >> $GITHUB_ENV + echo "$COMPACT_HOME" >> $GITHUB_PATH + - name: Setup Environment uses: ./.github/actions/setup - with: - skip-compile: 'true' - name: Cleanup on failure if: failure() diff --git a/.github/workflows/contracts-test.yml b/.github/workflows/contracts-test.yml index 299f305d..92933532 100644 --- a/.github/workflows/contracts-test.yml +++ b/.github/workflows/contracts-test.yml @@ -10,17 +10,52 @@ concurrency: group: contracts-test-${{ github.run_id }}-${{ github.ref }} cancel-in-progress: true +env: + TURBO_TELEMETRY_DISABLED: 1 + jobs: test: name: Test Contracts runs-on: ubuntu-22.04 steps: + - name: Check out code + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Recommended by turbo team + + - name: Install Compact compiler + id: setup + shell: bash + run: | + # Set version variables + COMPILER_VERSION="0.23.0" + LANGUAGE_VERSION="0.15.0" + + # Create directory for compiler + COMPACT_HOME="$HOME/compactc" + mkdir -p "$COMPACT_HOME" + cd "$COMPACT_HOME" + + echo "⬇️ Downloading Compact compiler..." + cd "$COMPACT_HOME" + curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip + unzip compactc.zip + chmod +x compactc.bin zkir compactc + + # Verify installation + [ -f "$COMPACT_HOME/compactc" ] || { echo "::error::❌ Failed to install compiler - compactc not found"; exit 1; } + + # Test installation + "$COMPACT_HOME/compactc" --version + + # Set up environment variables + echo "COMPACT_HOME=$COMPACT_HOME" >> $GITHUB_ENV + echo "$COMPACT_HOME" >> $GITHUB_PATH + - name: Setup Environment uses: ./.github/actions/setup - with: - skip-compile: 'true' - + - name: Verify Compact build artifacts run: | if ! find contracts/*/src/artifacts -type d 2>/dev/null | grep -q .; then @@ -30,6 +65,7 @@ jobs: echo "✅ Compact build artifacts found" - name: Run contract tests + run: yarn test timeout-minutes: 15 diff --git a/.github/workflows/contracts-version.yml b/.github/workflows/contracts-version.yml new file mode 100644 index 00000000..952acf59 --- /dev/null +++ b/.github/workflows/contracts-version.yml @@ -0,0 +1,81 @@ +name: Contracts Version + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: contracts-version-${{ github.run_id }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + name: Check Contract Versions + runs-on: ubuntu-22.04 + + steps: + - name: Check out code + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Recommended by turbo team + + - name: Install Compact compiler + id: setup + shell: bash + run: | + # Set version variables + COMPILER_VERSION="0.23.0" + LANGUAGE_VERSION="0.15.0" + + # Create directory for compiler + COMPACT_HOME="$HOME/compactc" + mkdir -p "$COMPACT_HOME" + cd "$COMPACT_HOME" + + echo "⬇️ Downloading Compact compiler..." + cd "$COMPACT_HOME" + curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip + unzip compactc.zip + chmod +x compactc.bin zkir compactc + + # Verify installation + [ -f "$COMPACT_HOME/compactc" ] || { echo "::error::❌ Failed to install compiler - compactc not found"; exit 1; } + + # Test installation + "$COMPACT_HOME/compactc" --version + + # Set up environment variables + echo "COMPACT_HOME=$COMPACT_HOME" >> $GITHUB_ENV + echo "$COMPACT_HOME" >> $GITHUB_PATH + + - name: Check compiler version + run: | + EXPECTED_COMPILER_VERSION="0.23.0" + COMPILER_OUTPUT=$("$COMPACT_HOME/compactc" --version) + COMPILER_VERSION=$(echo "$COMPILER_OUTPUT" | grep -oP '\b0\.[0-9]+\.[0-9]+\b' | head -n 1) + if [ "$COMPILER_VERSION" != "$EXPECTED_COMPILER_VERSION" ]; then + errMsg="❌ Compiler version mismatch!%0AExpected: $EXPECTED_COMPILER_VERSION%0AGot: $COMPILER_VERSION" + echo "::error::$errMsg" + exit 1 + fi + echo "✅ Compiler version matches: $COMPILER_VERSION" + + - name: Check language version + run: | + EXPECTED_LANGUAGE_VERSION="0.15.0" + LANGUAGE_OUTPUT=$("$COMPACT_HOME/compactc" --language-version) + LANGUAGE_VERSION=$(echo "$LANGUAGE_OUTPUT" | grep -oP '\b0\.[0-9]+\.[0-9]+\b' | tail -n 1) + if [ "$LANGUAGE_VERSION" != "$EXPECTED_LANGUAGE_VERSION" ]; then + errMsg="❌ Language version mismatch!%0AExpected: $EXPECTED_LANGUAGE_VERSION%0AGot: $LANGUAGE_VERSION" + echo "::error::$errMsg" + exit 1 + fi + echo "✅ Language version matches: $LANGUAGE_VERSION" + + - name: Cleanup on failure + if: failure() + run: | + echo "Version check failed. Cleaning up..." + rm -rf contracts/*/src/artifacts/ \ No newline at end of file diff --git a/.github/workflows/compact-compiler.yml b/.github/workflows/install-compiler.yml similarity index 58% rename from .github/workflows/compact-compiler.yml rename to .github/workflows/install-compiler.yml index 38a96e56..22934312 100644 --- a/.github/workflows/compact-compiler.yml +++ b/.github/workflows/install-compiler.yml @@ -1,10 +1,7 @@ name: Install Compact Compiler on: - push: - branches: [main] - pull_request: - branches: [main] + workflow_call: env: COMPACT_HOME: $HOME/compactc @@ -15,18 +12,12 @@ jobs: runs-on: ubuntu-22.04 steps: - - name: Cache Compact compiler - uses: actions/cache@v4 - id: cache-compact + - name: Check out code + uses: actions/checkout@v4 with: - path: ${{ env.COMPACT_HOME }} - key: compact-compiler-0.23.0 - restore-keys: | - compact-compiler- + fetch-depth: 2 # Recommended by turbo team - - name: Install Compact compiler - if: steps.cache-compact.outputs.cache-hit != 'true' - id: setup + - name: Archive compactc binaries shell: bash run: | COMPILER_VERSION="0.23.0" @@ -40,4 +31,13 @@ jobs: chmod +x compactc.bin zkir compactc # Test installation - "${{ env.COMPACT_HOME }}/compactc" --version \ No newline at end of file + "${{ env.COMPACT_HOME }}/compactc" --version + - uses: actions/upload-artifact@v4 + with: + name: compactc-binaries + if-no-files-found: error + include-hidden-files: 'true' + path: | + home/runner/compactc/* + !home/runner/compactc/*.zip + !home/runner/compactc/lib/ diff --git a/compact/package.json b/compact/package.json index 7694d2ac..4419076e 100644 --- a/compact/package.json +++ b/compact/package.json @@ -17,7 +17,7 @@ "compact-compiler": "dist/runCompiler.js" }, "scripts": { - "build": "tsc -p .", + "build": "tsc -p .", "types": "tsc -p tsconfig.json --noEmit", "fmt": "biome format", "fmt:fix": "biome format --write", diff --git a/compact/turbo.json b/compact/turbo.json index 7e7bb2c7..5d208997 100644 --- a/compact/turbo.json +++ b/compact/turbo.json @@ -9,4 +9,4 @@ "cache": true } } -} \ No newline at end of file +} diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 89b3ead2..7a8a3099 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -14,8 +14,8 @@ } }, "scripts": { - "compact": "npx compact-compiler", - "build": "npx compact-builder && tsc", + "compact": "compact-compiler", + "build": "compact-builder && tsc", "test": "vitest run", "types": "tsc -p tsconfig.json --noEmit", "fmt": "biome format", diff --git a/package.json b/package.json index c0789e2a..fd304935 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "docs:watch": "npx turbo run docs:watch --filter=docs", "compact": "turbo run compact", "build": "turbo run build", + "build:compact": "turbo run build --filter=@openzeppelin-midnight/compact", "test": "turbo run test", "fmt": "turbo run fmt", "fmt:fix": "turbo run fmt:fix", From f1edf7aee245b475f511951f5159b59ab482cfbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 05:11:21 -0400 Subject: [PATCH 145/282] Use different ref --- .github/workflows/checks.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 07eca398..c82bbc88 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -20,6 +20,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 2 # Recommended by turbo team + ref: ${{ github.event.pull_request.head.sha }} - name: Setup Environment uses: ./.github/actions/setup From f457350a5c4ea5426700d6999da7cc49fd678a93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 05:13:49 -0400 Subject: [PATCH 146/282] Update fetch depth --- .github/workflows/checks.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index c82bbc88..ab5cc53d 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -19,8 +19,7 @@ jobs: - name: Check out code uses: actions/checkout@v4 with: - fetch-depth: 2 # Recommended by turbo team - ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 # Recommended by turbo team - name: Setup Environment uses: ./.github/actions/setup From 364b8a73689a784f516a53fe136acbdec911c1da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 05:20:37 -0400 Subject: [PATCH 147/282] revert change --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index ab5cc53d..07eca398 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -19,7 +19,7 @@ jobs: - name: Check out code uses: actions/checkout@v4 with: - fetch-depth: 0 # Recommended by turbo team + fetch-depth: 2 # Recommended by turbo team - name: Setup Environment uses: ./.github/actions/setup From 3ec89a659653391ea3bf2440c314462b39b7996a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 05:35:33 -0400 Subject: [PATCH 148/282] Update caching --- .github/actions/setup/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 37c6e7bc..7ea6c4ca 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -28,9 +28,9 @@ runs: uses: actions/cache@v4 with: path: .turbo - key: ${{ runner.os }}-turbo-${{ github.sha }} + key: ${{ runner.os }}-turbo-${{ hashFiles('.turbo/*') }}-${{ github.sha }} restore-keys: | - ${{ runner.os }}-turbo- + ${{ runner.os }}-turbo-${{ hashFiles('.turbo/*') }} - name: Setup Node.js uses: actions/setup-node@v4 From 2b0e5e9b3f2a5161d2f0119a3d5a7eabbd8bd0de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 07:46:18 -0400 Subject: [PATCH 149/282] Add dependabot.yml --- .github/dependabot.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..cb8ec33e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 5 + rebase-strategy: "auto" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" \ No newline at end of file From 6a8699e3e519ab17daff9c0a4ed9d23d855b7e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:06:53 -0400 Subject: [PATCH 150/282] Add fmt:ci turbo task --- .github/workflows/checks.yml | 6 +----- biome.json | 5 +++-- compact/package.json | 1 + contracts/utils/package.json | 1 + package.json | 1 + turbo.json | 4 ++++ 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 07eca398..d0226c05 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -26,12 +26,8 @@ jobs: with: skip-compile: 'true' - - name: Lint - run: yarn lint - timeout-minutes: 10 - - name: Format - run: yarn fmt + run: yarn fmt:ci timeout-minutes: 10 - name: Cleanup on failure diff --git a/biome.json b/biome.json index a9bc3f3a..2905c7ef 100644 --- a/biome.json +++ b/biome.json @@ -1,9 +1,10 @@ { "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "vcs": { - "enabled": false, + "enabled": true, "clientKind": "git", - "useIgnoreFile": false + "useIgnoreFile": true, + "defaultBranch": "main" }, "files": { "ignoreUnknown": false, diff --git a/compact/package.json b/compact/package.json index 4419076e..5ee332dc 100644 --- a/compact/package.json +++ b/compact/package.json @@ -21,6 +21,7 @@ "types": "tsc -p tsconfig.json --noEmit", "fmt": "biome format", "fmt:fix": "biome format --write", + "fmt:ci": "biome ci --changed", "lint": "biome lint", "lint:fix": "biome check --write", "clean": "git clean -fXd" diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 7a8a3099..71bbad45 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -20,6 +20,7 @@ "types": "tsc -p tsconfig.json --noEmit", "fmt": "biome format", "fmt:fix": "biome format --write", + "fmt:ci": "biome ci --changed", "lint": "biome lint", "lint:fix": "biome check --write", "clean": "git clean -fXd" diff --git a/package.json b/package.json index fd304935..c787d4c2 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "test": "turbo run test", "fmt": "turbo run fmt", "fmt:fix": "turbo run fmt:fix", + "fmt:ci": "turbo run fmt:ci", "fmt:rootDir": "biome format . --write", "lint": "turbo run lint", "lint:fix": "turbo run lint:fix", diff --git a/turbo.json b/turbo.json index 630131f6..24596117 100644 --- a/turbo.json +++ b/turbo.json @@ -37,6 +37,10 @@ "outputs": [], "cache": false }, + "fmt:ci": { + "outputs": [], + "cache": false + }, "lint": { "outputs": [], "cache": false From 76cc11887056ef5a5b9baa22c164906d53446815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:07:02 -0400 Subject: [PATCH 151/282] Remove file --- contracts/utils/js-resolver.cjs | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 contracts/utils/js-resolver.cjs diff --git a/contracts/utils/js-resolver.cjs b/contracts/utils/js-resolver.cjs deleted file mode 100644 index 19b6f50c..00000000 --- a/contracts/utils/js-resolver.cjs +++ /dev/null @@ -1,20 +0,0 @@ -const jsResolver = (path, options) => { - const jsExtRegex = /\.js$/i; - const resolver = options.defaultResolver; - if ( - jsExtRegex.test(path) && - !options.basedir.includes('node_modules') && - !path.includes('node_modules') - ) { - const newPath = path.replace(jsExtRegex, '.ts'); - try { - return resolver(newPath, options); - } catch { - // use default resolver - } - } - - return resolver(path, options); -}; - -module.exports = jsResolver; From 1d1cd4e57bbbbb1e0386c632cfe6eaa605723ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:09:54 -0400 Subject: [PATCH 152/282] Disable telemetry --- .github/workflows/checks.yml | 3 +++ .github/workflows/contracts-build.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index d0226c05..6b4c93a9 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -1,5 +1,8 @@ name: Checks +env: + TURBO_TELEMETRY_DISABLED: 1 + on: push: branches: [main] diff --git a/.github/workflows/contracts-build.yml b/.github/workflows/contracts-build.yml index 218a2978..225ef963 100644 --- a/.github/workflows/contracts-build.yml +++ b/.github/workflows/contracts-build.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [main] +env: + TURBO_TELEMETRY_DISABLED: 1 + concurrency: group: contracts-build-${{ github.run_id }}-${{ github.ref }} cancel-in-progress: true From 98853b7e671d8839a79c733d342ac83b6bdb0eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:10:01 -0400 Subject: [PATCH 153/282] Remove file --- .github/workflows/install-compiler.yml | 43 -------------------------- 1 file changed, 43 deletions(-) delete mode 100644 .github/workflows/install-compiler.yml diff --git a/.github/workflows/install-compiler.yml b/.github/workflows/install-compiler.yml deleted file mode 100644 index 22934312..00000000 --- a/.github/workflows/install-compiler.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Install Compact Compiler - -on: - workflow_call: - -env: - COMPACT_HOME: $HOME/compactc - -jobs: - install: - name: Install Compact Compiler - runs-on: ubuntu-22.04 - - steps: - - name: Check out code - uses: actions/checkout@v4 - with: - fetch-depth: 2 # Recommended by turbo team - - - name: Archive compactc binaries - shell: bash - run: | - COMPILER_VERSION="0.23.0" - LANGUAGE_VERSION="0.15.0" - mkdir -p "${{ env.COMPACT_HOME }}" - - echo "⬇️ Downloading Compact compiler..." - cd "${{ env.COMPACT_HOME }}" - curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip - unzip compactc.zip - chmod +x compactc.bin zkir compactc - - # Test installation - "${{ env.COMPACT_HOME }}/compactc" --version - - uses: actions/upload-artifact@v4 - with: - name: compactc-binaries - if-no-files-found: error - include-hidden-files: 'true' - path: | - home/runner/compactc/* - !home/runner/compactc/*.zip - !home/runner/compactc/lib/ From 1a24649a48216af1b28ee8b9a1c15fe1546fc997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:12:11 -0400 Subject: [PATCH 154/282] Add no-errors-on-unmatched flag to fmt:ci task --- compact/package.json | 2 +- contracts/utils/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compact/package.json b/compact/package.json index 5ee332dc..3d247543 100644 --- a/compact/package.json +++ b/compact/package.json @@ -21,7 +21,7 @@ "types": "tsc -p tsconfig.json --noEmit", "fmt": "biome format", "fmt:fix": "biome format --write", - "fmt:ci": "biome ci --changed", + "fmt:ci": "biome ci --changed --no-errors-on-unmatched", "lint": "biome lint", "lint:fix": "biome check --write", "clean": "git clean -fXd" diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 71bbad45..f75e9196 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -20,7 +20,7 @@ "types": "tsc -p tsconfig.json --noEmit", "fmt": "biome format", "fmt:fix": "biome format --write", - "fmt:ci": "biome ci --changed", + "fmt:ci": "biome ci --changed --no-errors-on-unmatched", "lint": "biome lint", "lint:fix": "biome check --write", "clean": "git clean -fXd" From e615127df6f49b8a5f3b57dd45a6b96551eeb559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 10:59:28 -0400 Subject: [PATCH 155/282] Update module resolution configs --- contracts/utils/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/tsconfig.json b/contracts/utils/tsconfig.json index 3e90b0a9..a6b072c2 100644 --- a/contracts/utils/tsconfig.json +++ b/contracts/utils/tsconfig.json @@ -7,7 +7,7 @@ "lib": ["ESNext"], "target": "ES2022", "module": "ESNext", - "moduleResolution": "node", + "moduleResolution": "node16", "allowJs": true, "forceConsistentCasingInFileNames": true, "noImplicitAny": true, From e95e915bac4d5c900c8e8cf57b8e7e0eaa2f7d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 11:25:08 -0400 Subject: [PATCH 156/282] Bump @types/node pkg --- compact/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compact/package.json b/compact/package.json index 3d247543..851d4766 100644 --- a/compact/package.json +++ b/compact/package.json @@ -27,7 +27,7 @@ "clean": "git clean -fXd" }, "devDependencies": { - "@types/node": "^22.13.10", + "@types/node": "^22.14.0", "fast-check": "^3.15.0", "typescript": "^5.8.2" }, From 9df6ad9b78d692482121b90898b80bef8b464135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:42:04 -0400 Subject: [PATCH 157/282] Fix issue with formatting files in project root --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index c787d4c2..fd304935 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "test": "turbo run test", "fmt": "turbo run fmt", "fmt:fix": "turbo run fmt:fix", - "fmt:ci": "turbo run fmt:ci", "fmt:rootDir": "biome format . --write", "lint": "turbo run lint", "lint:fix": "turbo run lint:fix", From 81f3554851c197dc3c55062a2ceb9595c92c6dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 20:45:23 -0400 Subject: [PATCH 158/282] Updates turbo.json --- compact/turbo.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compact/turbo.json b/compact/turbo.json index 5d208997..7e7bb2c7 100644 --- a/compact/turbo.json +++ b/compact/turbo.json @@ -9,4 +9,4 @@ "cache": true } } -} +} \ No newline at end of file From adc39385059b20bfb4b79b3529238eb302a6ab4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 22:23:49 -0400 Subject: [PATCH 159/282] Configure composite action --- .github/actions/setup/action.yml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 7ea6c4ca..48861f2b 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -1,12 +1,11 @@ -name: 'Setup Environment' -description: 'Sets up the environment with Compact compiler, yarn, and Node.js' -timeout-minutes: 15 +name: "Setup Environment" +description: "Sets up the environment with Compact compiler, yarn, and Node.js" inputs: skip-compile: - description: 'Skip the fast compile step' + description: "Skip the fast compile step" required: false - default: 'false' + default: "false" runs: using: "composite" @@ -23,7 +22,7 @@ runs: key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-yarn- - + - name: Cache turbo build setup uses: actions/cache@v4 with: @@ -35,13 +34,13 @@ runs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version-file: '.nvmrc' - cache: 'yarn' + node-version-file: ".nvmrc" + cache: "yarn" - name: Install dependencies shell: bash run: yarn install --immutable - + - name: Build compact package shell: bash env: @@ -65,7 +64,7 @@ runs: - name: Fast compile contracts (skip zk) env: - TURBO_TELEMETRY_DISABLED: 1 + TURBO_TELEMETRY_DISABLED: 1 if: ${{ inputs.skip-compile != 'true' }} shell: bash - run: yarn compact -- --skip-zk \ No newline at end of file + run: yarn compact -- --skip-zk From f3794eb17407d43237b7e9cf84cdd0f9b81c3339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 22:24:34 -0400 Subject: [PATCH 160/282] Configure CodeQL workflow --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 9470a1ce..99f20d31 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -27,7 +27,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 2 # Recommended by turbo team - + - name: Setup Environment uses: ./.github/actions/setup with: From 22a11117e4420e7cf6cf693aec2f65689987895d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 22:25:06 -0400 Subject: [PATCH 161/282] Configure workflow to test compact compiler install --- .github/workflows/compact-compiler.yml | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/compact-compiler.yml diff --git a/.github/workflows/compact-compiler.yml b/.github/workflows/compact-compiler.yml new file mode 100644 index 00000000..38a96e56 --- /dev/null +++ b/.github/workflows/compact-compiler.yml @@ -0,0 +1,43 @@ +name: Install Compact Compiler + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + COMPACT_HOME: $HOME/compactc + +jobs: + install: + name: Install Compact Compiler + runs-on: ubuntu-22.04 + + steps: + - name: Cache Compact compiler + uses: actions/cache@v4 + id: cache-compact + with: + path: ${{ env.COMPACT_HOME }} + key: compact-compiler-0.23.0 + restore-keys: | + compact-compiler- + + - name: Install Compact compiler + if: steps.cache-compact.outputs.cache-hit != 'true' + id: setup + shell: bash + run: | + COMPILER_VERSION="0.23.0" + LANGUAGE_VERSION="0.15.0" + mkdir -p "${{ env.COMPACT_HOME }}" + + echo "⬇️ Downloading Compact compiler..." + cd "${{ env.COMPACT_HOME }}" + curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip + unzip compactc.zip + chmod +x compactc.bin zkir compactc + + # Test installation + "${{ env.COMPACT_HOME }}/compactc" --version \ No newline at end of file From b31627210661d3fcac1ec96a72d1fc82939e0a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 23:42:27 -0400 Subject: [PATCH 162/282] Add contracts build workflow --- .github/workflows/contracts-build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/contracts-build.yml b/.github/workflows/contracts-build.yml index 225ef963..5e3b4768 100644 --- a/.github/workflows/contracts-build.yml +++ b/.github/workflows/contracts-build.yml @@ -28,7 +28,7 @@ jobs: uses: ./.github/actions/setup with: skip-compile: 'true' - + - name: Install Compact compiler id: setup shell: bash @@ -68,7 +68,7 @@ jobs: echo "::error::❌ Build artifacts not found in any contracts/*/artifacts or in packages/compact/dist!" exit 1 fi - + # List build artifacts echo "✅ Build artifacts found:" echo "Package build artifacts (dist):" From 5c50712207e2bd6cca630a879932ef920eb8bb0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 23:42:46 -0400 Subject: [PATCH 163/282] Add contracts compile workflow --- .github/workflows/contracts-compile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/contracts-compile.yml b/.github/workflows/contracts-compile.yml index b3a2b8c9..7f188681 100644 --- a/.github/workflows/contracts-compile.yml +++ b/.github/workflows/contracts-compile.yml @@ -26,7 +26,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 2 # Recommended by turbo team - + - name: Install Compact compiler id: setup shell: bash From 15d737e689ada9a6f353e17586b1ea6b9a4d45ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 11 Jun 2025 23:43:27 -0400 Subject: [PATCH 164/282] Refator workflows --- ...pact-compiler.yml => install-compiler.yml} | 30 +++++++++---------- compact/turbo.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) rename .github/workflows/{compact-compiler.yml => install-compiler.yml} (58%) diff --git a/.github/workflows/compact-compiler.yml b/.github/workflows/install-compiler.yml similarity index 58% rename from .github/workflows/compact-compiler.yml rename to .github/workflows/install-compiler.yml index 38a96e56..22934312 100644 --- a/.github/workflows/compact-compiler.yml +++ b/.github/workflows/install-compiler.yml @@ -1,10 +1,7 @@ name: Install Compact Compiler on: - push: - branches: [main] - pull_request: - branches: [main] + workflow_call: env: COMPACT_HOME: $HOME/compactc @@ -15,18 +12,12 @@ jobs: runs-on: ubuntu-22.04 steps: - - name: Cache Compact compiler - uses: actions/cache@v4 - id: cache-compact + - name: Check out code + uses: actions/checkout@v4 with: - path: ${{ env.COMPACT_HOME }} - key: compact-compiler-0.23.0 - restore-keys: | - compact-compiler- + fetch-depth: 2 # Recommended by turbo team - - name: Install Compact compiler - if: steps.cache-compact.outputs.cache-hit != 'true' - id: setup + - name: Archive compactc binaries shell: bash run: | COMPILER_VERSION="0.23.0" @@ -40,4 +31,13 @@ jobs: chmod +x compactc.bin zkir compactc # Test installation - "${{ env.COMPACT_HOME }}/compactc" --version \ No newline at end of file + "${{ env.COMPACT_HOME }}/compactc" --version + - uses: actions/upload-artifact@v4 + with: + name: compactc-binaries + if-no-files-found: error + include-hidden-files: 'true' + path: | + home/runner/compactc/* + !home/runner/compactc/*.zip + !home/runner/compactc/lib/ diff --git a/compact/turbo.json b/compact/turbo.json index 7e7bb2c7..5d208997 100644 --- a/compact/turbo.json +++ b/compact/turbo.json @@ -9,4 +9,4 @@ "cache": true } } -} \ No newline at end of file +} From b9d129455b1a9f1528e448690bad6083ea7805b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 05:11:21 -0400 Subject: [PATCH 165/282] Use different ref --- .github/workflows/checks.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 6b4c93a9..f42dae7c 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -23,6 +23,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 2 # Recommended by turbo team + ref: ${{ github.event.pull_request.head.sha }} - name: Setup Environment uses: ./.github/actions/setup From 0a5f69dad17e48cfc85ea99e2abc08f9bec54f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 05:13:49 -0400 Subject: [PATCH 166/282] Update fetch depth --- .github/workflows/checks.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index f42dae7c..f4f2786e 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -22,8 +22,7 @@ jobs: - name: Check out code uses: actions/checkout@v4 with: - fetch-depth: 2 # Recommended by turbo team - ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 # Recommended by turbo team - name: Setup Environment uses: ./.github/actions/setup From c8c137039f070c44dbe21d1df6b331de35af6d51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 05:20:37 -0400 Subject: [PATCH 167/282] revert change --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index f4f2786e..6b4c93a9 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -22,7 +22,7 @@ jobs: - name: Check out code uses: actions/checkout@v4 with: - fetch-depth: 0 # Recommended by turbo team + fetch-depth: 2 # Recommended by turbo team - name: Setup Environment uses: ./.github/actions/setup From f78116542f62fbb97fa0ea60d286d9936009944f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:06:53 -0400 Subject: [PATCH 168/282] Add fmt:ci turbo task --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index fd304935..c787d4c2 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "test": "turbo run test", "fmt": "turbo run fmt", "fmt:fix": "turbo run fmt:fix", + "fmt:ci": "turbo run fmt:ci", "fmt:rootDir": "biome format . --write", "lint": "turbo run lint", "lint:fix": "turbo run lint:fix", From 7c7a91ee5233fa3215934f82fa6f780cea97b0e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:10:01 -0400 Subject: [PATCH 169/282] Remove file --- .github/workflows/install-compiler.yml | 43 -------------------------- 1 file changed, 43 deletions(-) delete mode 100644 .github/workflows/install-compiler.yml diff --git a/.github/workflows/install-compiler.yml b/.github/workflows/install-compiler.yml deleted file mode 100644 index 22934312..00000000 --- a/.github/workflows/install-compiler.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Install Compact Compiler - -on: - workflow_call: - -env: - COMPACT_HOME: $HOME/compactc - -jobs: - install: - name: Install Compact Compiler - runs-on: ubuntu-22.04 - - steps: - - name: Check out code - uses: actions/checkout@v4 - with: - fetch-depth: 2 # Recommended by turbo team - - - name: Archive compactc binaries - shell: bash - run: | - COMPILER_VERSION="0.23.0" - LANGUAGE_VERSION="0.15.0" - mkdir -p "${{ env.COMPACT_HOME }}" - - echo "⬇️ Downloading Compact compiler..." - cd "${{ env.COMPACT_HOME }}" - curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip - unzip compactc.zip - chmod +x compactc.bin zkir compactc - - # Test installation - "${{ env.COMPACT_HOME }}/compactc" --version - - uses: actions/upload-artifact@v4 - with: - name: compactc-binaries - if-no-files-found: error - include-hidden-files: 'true' - path: | - home/runner/compactc/* - !home/runner/compactc/*.zip - !home/runner/compactc/lib/ From bd6faa007f7c1fb2709d20f67b121eccffb71033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 16:55:02 -0400 Subject: [PATCH 170/282] Update Setup Composite Action, Introduce Compact Test Suite Workflow --- .github/actions/setup/action.yml | 5 +- .github/workflows/contracts-test-suite.yml | 98 ++++++++++++++++++++++ 2 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/contracts-test-suite.yml diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 48861f2b..38b6512a 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -27,9 +27,9 @@ runs: uses: actions/cache@v4 with: path: .turbo - key: ${{ runner.os }}-turbo-${{ hashFiles('.turbo/*') }}-${{ github.sha }} + key: ${{ runner.os }}-turbo-${{ github.sha }} restore-keys: | - ${{ runner.os }}-turbo-${{ hashFiles('.turbo/*') }} + ${{ runner.os }}-turbo- - name: Setup Node.js uses: actions/setup-node@v4 @@ -44,6 +44,7 @@ runs: - name: Build compact package shell: bash env: + TURBO_MAJOR_VERSION: 2 TURBO_TELEMETRY_DISABLED: 1 run: | yarn build:compact diff --git a/.github/workflows/contracts-test-suite.yml b/.github/workflows/contracts-test-suite.yml new file mode 100644 index 00000000..761a747c --- /dev/null +++ b/.github/workflows/contracts-test-suite.yml @@ -0,0 +1,98 @@ +name: Compact Contracts Test Suite + +on: + push: + paths: + - 'contracts/**/*.compact' + - 'contracts/**/*.test.ts' + +env: + TURBO_TELEMETRY_DISABLED: 1 + +jobs: + run-suite: + name: Run Test Suite + runs-on: ubuntu-24.04 + timeout-minutes: 15 + + steps: + - name: Check out code + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Recommended by turbo team + + - name: Setup Environment + uses: ./.github/actions/setup + + - name: Build compact package + shell: bash + run: | + cd compact + turbo build + cd .. + + - name: Validate build artifacts + shell: bash + run: | + REQUIRED_FILES=( + "compact/dist/runCompiler.js" + "compact/dist/runBuilder.js" + ) + for file in "${REQUIRED_FILES[@]}"; do + if [ ! -f "$file" ]; then + echo "::error::❌ Missing required file: $file" + exit 1 + fi + done + + - name: Install Compact compiler + id: setup + shell: bash + run: | + # Set version variables + COMPILER_VERSION="0.23.0" + LANGUAGE_VERSION="0.15.0" + + # Create directory for compiler + COMPACT_HOME="$HOME/compactc" + mkdir -p "$COMPACT_HOME" + cd "$COMPACT_HOME" + + echo "⬇️ Downloading Compact compiler..." + curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip + unzip compactc.zip + chmod +x compactc.bin zkir compactc + + # Set up environment variables + echo "COMPACT_HOME=$COMPACT_HOME" >> $GITHUB_ENV + echo "$COMPACT_HOME" >> $GITHUB_PATH + + # Verify installation + [ -f "$COMPACT_HOME/compactc" ] || { echo "::error::❌ Failed to install compiler - compactc not found"; exit 1; } + + # Test installation + compactc --version + + - name: Check compiler version + run: | + EXPECTED_COMPILER_VERSION="0.23.0" + COMPILER_OUTPUT=$(compactc --version) + COMPILER_VERSION=$(echo "$COMPILER_OUTPUT" | grep -oP '\b0\.[0-9]+\.[0-9]+\b' | head -n 1) + if [ "$COMPILER_VERSION" != "$EXPECTED_COMPILER_VERSION" ]; then + errMsg="❌ Compiler version mismatch!%0AExpected: $EXPECTED_COMPILER_VERSION%0AGot: $COMPILER_VERSION" + echo "::error::$errMsg" + exit 1 + fi + echo "✅ Compiler version matches: $COMPILER_VERSION" + + - name: Check language version + run: | + EXPECTED_LANGUAGE_VERSION="0.15.0" + LANGUAGE_OUTPUT=$(compactc --language-version) + LANGUAGE_VERSION=$(echo "$LANGUAGE_OUTPUT" | grep -oP '\b0\.[0-9]+\.[0-9]+\b' | tail -n 1) + if [ "$LANGUAGE_VERSION" != "$EXPECTED_LANGUAGE_VERSION" ]; then + errMsg="❌ Language version mismatch!%0AExpected: $EXPECTED_LANGUAGE_VERSION%0AGot: $LANGUAGE_VERSION" + echo "::error::$errMsg" + exit 1 + fi + echo "✅ Language version matches: $LANGUAGE_VERSION" \ No newline at end of file From 5eb8f875c315a4c2fa912a177a34a798d0215a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 17:05:43 -0400 Subject: [PATCH 171/282] Update workflow trigger for testing --- .github/workflows/contracts-test-suite.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/contracts-test-suite.yml b/.github/workflows/contracts-test-suite.yml index 761a747c..81ae117b 100644 --- a/.github/workflows/contracts-test-suite.yml +++ b/.github/workflows/contracts-test-suite.yml @@ -1,10 +1,10 @@ name: Compact Contracts Test Suite on: - push: - paths: - - 'contracts/**/*.compact' - - 'contracts/**/*.test.ts' + push + # paths: + # - 'contracts/**/*.compact' + # - 'contracts/**/*.test.ts' env: TURBO_TELEMETRY_DISABLED: 1 From 6a622c309671c423306e52bab873464e2b286b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 18:05:26 -0400 Subject: [PATCH 172/282] Update test suite --- .github/workflows/contracts-test-suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/contracts-test-suite.yml b/.github/workflows/contracts-test-suite.yml index 81ae117b..74076c6e 100644 --- a/.github/workflows/contracts-test-suite.yml +++ b/.github/workflows/contracts-test-suite.yml @@ -71,7 +71,7 @@ jobs: [ -f "$COMPACT_HOME/compactc" ] || { echo "::error::❌ Failed to install compiler - compactc not found"; exit 1; } # Test installation - compactc --version + $COMPACT_HOME/compactc" --version - name: Check compiler version run: | From 880d798f049b78d91a5c23aa5f406509273fb1d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 18:32:28 -0400 Subject: [PATCH 173/282] Consolidate Contracts Tests in Single Test Suite --- .github/workflows/contracts-build.yml | 84 ---------------------- .github/workflows/contracts-compile.yml | 66 ----------------- .github/workflows/contracts-test-suite.yml | 23 +++++- .github/workflows/contracts-test.yml | 78 -------------------- .github/workflows/contracts-version.yml | 81 --------------------- 5 files changed, 22 insertions(+), 310 deletions(-) delete mode 100644 .github/workflows/contracts-build.yml delete mode 100644 .github/workflows/contracts-compile.yml delete mode 100644 .github/workflows/contracts-test.yml delete mode 100644 .github/workflows/contracts-version.yml diff --git a/.github/workflows/contracts-build.yml b/.github/workflows/contracts-build.yml deleted file mode 100644 index 5e3b4768..00000000 --- a/.github/workflows/contracts-build.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: Contracts Build - -on: - push: - branches: [main] - pull_request: - branches: [main] - -env: - TURBO_TELEMETRY_DISABLED: 1 - -concurrency: - group: contracts-build-${{ github.run_id }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - name: Build Compact Contracts - runs-on: ubuntu-22.04 - - steps: - - name: Check out code - uses: actions/checkout@v4 - with: - fetch-depth: 2 # Recommended by turbo team - - - name: Setup Environment - uses: ./.github/actions/setup - with: - skip-compile: 'true' - - - name: Install Compact compiler - id: setup - shell: bash - run: | - # Set version variables - COMPILER_VERSION="0.23.0" - LANGUAGE_VERSION="0.15.0" - - # Create directory for compiler - COMPACT_HOME="$HOME/compactc" - mkdir -p "$COMPACT_HOME" - cd "$COMPACT_HOME" - - echo "⬇️ Downloading Compact compiler..." - cd "$COMPACT_HOME" - curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip - unzip compactc.zip - chmod +x compactc.bin zkir compactc - - # Verify installation - [ -f "$COMPACT_HOME/compactc" ] || { echo "::error::❌ Failed to install compiler - compactc not found"; exit 1; } - - # Test installation - "$COMPACT_HOME/compactc" --version - - # Set up environment variables - echo "COMPACT_HOME=$COMPACT_HOME" >> $GITHUB_ENV - echo "$COMPACT_HOME" >> $GITHUB_PATH - - - name: Build contracts - run: yarn build - timeout-minutes: 10 - - - name: Check if build artifacts exist - run: | - if ! find contracts -type d -name artifacts | grep -q . && [ ! -d "packages/compact/dist" ]; then - echo "::error::❌ Build artifacts not found in any contracts/*/artifacts or in packages/compact/dist!" - exit 1 - fi - - # List build artifacts - echo "✅ Build artifacts found:" - echo "Package build artifacts (dist):" - find contracts -name "dist" -type d -exec ls -la {} \; - echo -e "\nCompact code artifacts (src/artifacts):" - find contracts -name "artifacts" -type d -exec ls -la {} \; - - - name: Cleanup on failure - if: failure() - run: | - echo "Build failed. Cleaning up..." - rm -rf contracts/*/dist/ - rm -rf contracts/*/src/artifacts/ \ No newline at end of file diff --git a/.github/workflows/contracts-compile.yml b/.github/workflows/contracts-compile.yml deleted file mode 100644 index 7f188681..00000000 --- a/.github/workflows/contracts-compile.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: Contracts Compile - -on: - push: - branches: [main] - pull_request: - branches: [main] - -permissions: - checks: write - actions: write - contents: read - -concurrency: - group: contracts-compile-${{ github.run_id }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - compile: - name: Fast Compile Contracts - runs-on: ubuntu-22.04 - timeout-minutes: 15 - - steps: - - name: Check out code - uses: actions/checkout@v4 - with: - fetch-depth: 2 # Recommended by turbo team - - - name: Install Compact compiler - id: setup - shell: bash - run: | - # Set version variables - COMPILER_VERSION="0.23.0" - LANGUAGE_VERSION="0.15.0" - - # Create directory for compiler - COMPACT_HOME="$HOME/compactc" - mkdir -p "$COMPACT_HOME" - cd "$COMPACT_HOME" - - echo "⬇️ Downloading Compact compiler..." - cd "$COMPACT_HOME" - curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip - unzip compactc.zip - chmod +x compactc.bin zkir compactc - - # Verify installation - [ -f "$COMPACT_HOME/compactc" ] || { echo "::error::❌ Failed to install compiler - compactc not found"; exit 1; } - - # Test installation - "$COMPACT_HOME/compactc" --version - - # Set up environment variables - echo "COMPACT_HOME=$COMPACT_HOME" >> $GITHUB_ENV - echo "$COMPACT_HOME" >> $GITHUB_PATH - - - name: Setup Environment - uses: ./.github/actions/setup - - - name: Cleanup on failure - if: failure() - run: | - echo "Compilation failed. Cleaning up..." - rm -rf contracts/*/src/artifacts/ \ No newline at end of file diff --git a/.github/workflows/contracts-test-suite.yml b/.github/workflows/contracts-test-suite.yml index 74076c6e..c40f86e2 100644 --- a/.github/workflows/contracts-test-suite.yml +++ b/.github/workflows/contracts-test-suite.yml @@ -95,4 +95,25 @@ jobs: echo "::error::$errMsg" exit 1 fi - echo "✅ Language version matches: $LANGUAGE_VERSION" \ No newline at end of file + echo "✅ Language version matches: $LANGUAGE_VERSION" + + - name: Build contracts + run: turbo build --filter="./contracts/*" + timeout-minutes: 10 + + - name: Check if build artifacts exist + run: | + if ! find contracts -type d -name artifacts | grep -q . ; then + echo "::error::❌ Build artifacts not found in any contracts/*/artifacts" + exit 1 + fi + + # List build artifacts + echo "✅ Build artifacts found:" + echo "Package build artifacts (dist):" + find contracts -name "dist" -type d -exec ls -la {} \; + echo -e "\nCompact code artifacts (src/artifacts):" + find contracts -name "artifacts" -type d -exec ls -la {} \; + + - name: Run Contract Tests + run: turbo test \ No newline at end of file diff --git a/.github/workflows/contracts-test.yml b/.github/workflows/contracts-test.yml deleted file mode 100644 index 92933532..00000000 --- a/.github/workflows/contracts-test.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Contracts Test - -on: - push: - branches: [main] - pull_request: - branches: [main] - -concurrency: - group: contracts-test-${{ github.run_id }}-${{ github.ref }} - cancel-in-progress: true - -env: - TURBO_TELEMETRY_DISABLED: 1 - -jobs: - test: - name: Test Contracts - runs-on: ubuntu-22.04 - - steps: - - name: Check out code - uses: actions/checkout@v4 - with: - fetch-depth: 2 # Recommended by turbo team - - - name: Install Compact compiler - id: setup - shell: bash - run: | - # Set version variables - COMPILER_VERSION="0.23.0" - LANGUAGE_VERSION="0.15.0" - - # Create directory for compiler - COMPACT_HOME="$HOME/compactc" - mkdir -p "$COMPACT_HOME" - cd "$COMPACT_HOME" - - echo "⬇️ Downloading Compact compiler..." - cd "$COMPACT_HOME" - curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip - unzip compactc.zip - chmod +x compactc.bin zkir compactc - - # Verify installation - [ -f "$COMPACT_HOME/compactc" ] || { echo "::error::❌ Failed to install compiler - compactc not found"; exit 1; } - - # Test installation - "$COMPACT_HOME/compactc" --version - - # Set up environment variables - echo "COMPACT_HOME=$COMPACT_HOME" >> $GITHUB_ENV - echo "$COMPACT_HOME" >> $GITHUB_PATH - - - name: Setup Environment - uses: ./.github/actions/setup - - - name: Verify Compact build artifacts - run: | - if ! find contracts/*/src/artifacts -type d 2>/dev/null | grep -q .; then - echo "::error::❌ Compact build artifacts not found!" - exit 1 - fi - echo "✅ Compact build artifacts found" - - - name: Run contract tests - - run: yarn test - timeout-minutes: 15 - - - name: Cleanup on failure - if: failure() - run: | - echo "Tests failed. Cleaning up..." - rm -rf contracts/*/dist/ - rm -rf contracts/*/src/artifacts/ - \ No newline at end of file diff --git a/.github/workflows/contracts-version.yml b/.github/workflows/contracts-version.yml deleted file mode 100644 index 952acf59..00000000 --- a/.github/workflows/contracts-version.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: Contracts Version - -on: - push: - branches: [main] - pull_request: - branches: [main] - -concurrency: - group: contracts-version-${{ github.run_id }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - check: - name: Check Contract Versions - runs-on: ubuntu-22.04 - - steps: - - name: Check out code - uses: actions/checkout@v4 - with: - fetch-depth: 2 # Recommended by turbo team - - - name: Install Compact compiler - id: setup - shell: bash - run: | - # Set version variables - COMPILER_VERSION="0.23.0" - LANGUAGE_VERSION="0.15.0" - - # Create directory for compiler - COMPACT_HOME="$HOME/compactc" - mkdir -p "$COMPACT_HOME" - cd "$COMPACT_HOME" - - echo "⬇️ Downloading Compact compiler..." - cd "$COMPACT_HOME" - curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip - unzip compactc.zip - chmod +x compactc.bin zkir compactc - - # Verify installation - [ -f "$COMPACT_HOME/compactc" ] || { echo "::error::❌ Failed to install compiler - compactc not found"; exit 1; } - - # Test installation - "$COMPACT_HOME/compactc" --version - - # Set up environment variables - echo "COMPACT_HOME=$COMPACT_HOME" >> $GITHUB_ENV - echo "$COMPACT_HOME" >> $GITHUB_PATH - - - name: Check compiler version - run: | - EXPECTED_COMPILER_VERSION="0.23.0" - COMPILER_OUTPUT=$("$COMPACT_HOME/compactc" --version) - COMPILER_VERSION=$(echo "$COMPILER_OUTPUT" | grep -oP '\b0\.[0-9]+\.[0-9]+\b' | head -n 1) - if [ "$COMPILER_VERSION" != "$EXPECTED_COMPILER_VERSION" ]; then - errMsg="❌ Compiler version mismatch!%0AExpected: $EXPECTED_COMPILER_VERSION%0AGot: $COMPILER_VERSION" - echo "::error::$errMsg" - exit 1 - fi - echo "✅ Compiler version matches: $COMPILER_VERSION" - - - name: Check language version - run: | - EXPECTED_LANGUAGE_VERSION="0.15.0" - LANGUAGE_OUTPUT=$("$COMPACT_HOME/compactc" --language-version) - LANGUAGE_VERSION=$(echo "$LANGUAGE_OUTPUT" | grep -oP '\b0\.[0-9]+\.[0-9]+\b' | tail -n 1) - if [ "$LANGUAGE_VERSION" != "$EXPECTED_LANGUAGE_VERSION" ]; then - errMsg="❌ Language version mismatch!%0AExpected: $EXPECTED_LANGUAGE_VERSION%0AGot: $LANGUAGE_VERSION" - echo "::error::$errMsg" - exit 1 - fi - echo "✅ Language version matches: $LANGUAGE_VERSION" - - - name: Cleanup on failure - if: failure() - run: | - echo "Version check failed. Cleaning up..." - rm -rf contracts/*/src/artifacts/ \ No newline at end of file From 89892be0b8b93129518bb0129c843ee32142ec46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 18:50:36 -0400 Subject: [PATCH 174/282] Update checks workflow, remove unneccessary scripts --- .github/workflows/checks.yml | 30 ++++++++++-------------------- package.json | 2 -- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 6b4c93a9..7383bd92 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -1,22 +1,18 @@ -name: Checks +name: Format, Lint, Type Check env: TURBO_TELEMETRY_DISABLED: 1 on: - push: - branches: [main] - pull_request: - branches: [main] - -concurrency: - group: checks-${{ github.run_id }}-${{ github.ref }} - cancel-in-progress: true + push + # paths: + # - '**.ts' + # - '**.json' jobs: checks: name: Run Checks - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Check out code @@ -26,15 +22,9 @@ jobs: - name: Setup Environment uses: ./.github/actions/setup - with: - skip-compile: 'true' - - name: Format - run: yarn fmt:ci - timeout-minutes: 10 + - name: Format & Lint + run: yarn biome ci . --no-errors-on-unmatched && turbo fmt:ci - - name: Cleanup on failure - if: failure() - run: | - echo "Checks failed. Cleaning up..." - rm -rf contracts/*/src/artifacts/ \ No newline at end of file + - name: Run type checks + run: turbo types \ No newline at end of file diff --git a/package.json b/package.json index c787d4c2..64e6ebd5 100644 --- a/package.json +++ b/package.json @@ -14,12 +14,10 @@ "docs:watch": "npx turbo run docs:watch --filter=docs", "compact": "turbo run compact", "build": "turbo run build", - "build:compact": "turbo run build --filter=@openzeppelin-midnight/compact", "test": "turbo run test", "fmt": "turbo run fmt", "fmt:fix": "turbo run fmt:fix", "fmt:ci": "turbo run fmt:ci", - "fmt:rootDir": "biome format . --write", "lint": "turbo run lint", "lint:fix": "turbo run lint:fix", "types": "turbo run types", From c86bfeca776bab066e8b4dcadbce067dfbee37c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 18:58:23 -0400 Subject: [PATCH 175/282] fmt file --- package.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/package.json b/package.json index 64e6ebd5..602fe19e 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,7 @@ "description": "Secure Smart Contract library for Midnight", "private": true, "packageManager": "yarn@4.1.0", - "workspaces": [ - "compact/", - "contracts/*/", - "docs/" - ], + "workspaces": ["compact/", "contracts/*/", "docs/"], "scripts": { "prepare": "npx tsc -p ./compact && yarn rebuild", "docs": "npx turbo run docs --filter=docs", From 4e4d3cc78ec6a56f5bcd7659736a66daafd3e534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 18:58:35 -0400 Subject: [PATCH 176/282] Update turbo caching --- .github/actions/setup/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 38b6512a..0da41aea 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -27,9 +27,9 @@ runs: uses: actions/cache@v4 with: path: .turbo - key: ${{ runner.os }}-turbo-${{ github.sha }} + key: ${{ runner.os }}-turbo-${{ hashFiles('.turbo/*') }}-${{ github.sha }} restore-keys: | - ${{ runner.os }}-turbo- + ${{ runner.os }}-turbo-${{ hashFiles('.turbo/*') }} - name: Setup Node.js uses: actions/setup-node@v4 From 045eeeca6450424f3131daa95f91f757244e92bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 18:59:04 -0400 Subject: [PATCH 177/282] Update format and lint script --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 7383bd92..bbc26020 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -24,7 +24,7 @@ jobs: uses: ./.github/actions/setup - name: Format & Lint - run: yarn biome ci . --no-errors-on-unmatched && turbo fmt:ci + run: yarn biome ci . --changed --no-errors-on-unmatched && turbo fmt:ci - name: Run type checks run: turbo types \ No newline at end of file From e9c97133c7c9a9aebb01fe02aaf7017d311c2aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 19:34:16 -0400 Subject: [PATCH 178/282] Simplify biome tooling --- .github/workflows/checks.yml | 2 +- compact/package.json | 5 ----- contracts/utils/package.json | 5 ----- package.json | 8 +++----- turbo.json | 21 +++------------------ yarn.lock | 2 -- 6 files changed, 7 insertions(+), 36 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index bbc26020..c402d0b1 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -24,7 +24,7 @@ jobs: uses: ./.github/actions/setup - name: Format & Lint - run: yarn biome ci . --changed --no-errors-on-unmatched && turbo fmt:ci + run: turbo fmt-and-lint:ci - name: Run type checks run: turbo types \ No newline at end of file diff --git a/compact/package.json b/compact/package.json index 851d4766..b7cb4957 100644 --- a/compact/package.json +++ b/compact/package.json @@ -19,11 +19,6 @@ "scripts": { "build": "tsc -p .", "types": "tsc -p tsconfig.json --noEmit", - "fmt": "biome format", - "fmt:fix": "biome format --write", - "fmt:ci": "biome ci --changed --no-errors-on-unmatched", - "lint": "biome lint", - "lint:fix": "biome check --write", "clean": "git clean -fXd" }, "devDependencies": { diff --git a/contracts/utils/package.json b/contracts/utils/package.json index f75e9196..74fc46b2 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -18,11 +18,6 @@ "build": "compact-builder && tsc", "test": "vitest run", "types": "tsc -p tsconfig.json --noEmit", - "fmt": "biome format", - "fmt:fix": "biome format --write", - "fmt:ci": "biome ci --changed --no-errors-on-unmatched", - "lint": "biome lint", - "lint:fix": "biome check --write", "clean": "git clean -fXd" }, "dependencies": { diff --git a/package.json b/package.json index 602fe19e..953ee192 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,9 @@ "compact": "turbo run compact", "build": "turbo run build", "test": "turbo run test", - "fmt": "turbo run fmt", - "fmt:fix": "turbo run fmt:fix", - "fmt:ci": "turbo run fmt:ci", - "lint": "turbo run lint", - "lint:fix": "turbo run lint:fix", + "fmt-and-lint": "biome check . --changed", + "fmt-and-lint:fix": "biome check . --changed --write", + "fmt-and-lint:ci": "biome ci . --changed --no-errors-on-unmatched", "types": "turbo run types", "clean": "turbo run clean" }, diff --git a/turbo.json b/turbo.json index 24596117..428f1807 100644 --- a/turbo.json +++ b/turbo.json @@ -29,24 +29,9 @@ "cache": false, "dependsOn": ["compact"] }, - "fmt": { - "outputs": [], - "cache": false - }, - "fmt:fix": { - "outputs": [], - "cache": false - }, - "fmt:ci": { - "outputs": [], - "cache": false - }, - "lint": { - "outputs": [], - "cache": false - }, - "lint:fix": { - "outputs": [], + "//#fmt-and-lint": {}, + "//#fmt-and-lint:ci": {}, + "//#fmt-and-lint:fix": { "cache": false }, "clean": { diff --git a/yarn.lock b/yarn.lock index 52ce2668..7bdeaef7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -408,7 +408,6 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/erc20@workspace:contracts/erc20" dependencies: - "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:^18.18.6" ts-node: "npm:^10.9.2" @@ -447,7 +446,6 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" dependencies: - "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:^18.18.6" ts-node: "npm:^10.9.2" From 0fe7dc8515ca1203c8f16bb688647df39c7f598c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 20:08:16 -0400 Subject: [PATCH 179/282] Update turbo.json, Bump @types/node deps --- turbo.json | 3 +-- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/turbo.json b/turbo.json index 428f1807..d398fa4b 100644 --- a/turbo.json +++ b/turbo.json @@ -26,8 +26,7 @@ }, "types": { "outputs": [], - "cache": false, - "dependsOn": ["compact"] + "cache": false }, "//#fmt-and-lint": {}, "//#fmt-and-lint:ci": {}, diff --git a/yarn.lock b/yarn.lock index 7bdeaef7..c6ad338b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -392,7 +392,7 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/compact@workspace:compact" dependencies: - "@types/node": "npm:^22.13.10" + "@types/node": "npm:22.14.0" chalk: "npm:^5.4.1" fast-check: "npm:^3.15.0" log-symbols: "npm:^7.0.0" From ad0599d558317a0b7a86e0771007f537e380e634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 20:12:15 -0400 Subject: [PATCH 180/282] Fix missing double-quote --- .github/workflows/contracts-test-suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/contracts-test-suite.yml b/.github/workflows/contracts-test-suite.yml index c40f86e2..86e003b1 100644 --- a/.github/workflows/contracts-test-suite.yml +++ b/.github/workflows/contracts-test-suite.yml @@ -71,7 +71,7 @@ jobs: [ -f "$COMPACT_HOME/compactc" ] || { echo "::error::❌ Failed to install compiler - compactc not found"; exit 1; } # Test installation - $COMPACT_HOME/compactc" --version + "$COMPACT_HOME/compactc" --version - name: Check compiler version run: | From da12b42c07b8b792b84e5e68d21598bc3f4ce581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 20:26:58 -0400 Subject: [PATCH 181/282] Move type checks to contracts test suite --- .github/workflows/checks.yml | 7 ++----- .github/workflows/contracts-test-suite.yml | 3 +++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index c402d0b1..36ace3e2 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -1,4 +1,4 @@ -name: Format, Lint, Type Check +name: Format and Lint env: TURBO_TELEMETRY_DISABLED: 1 @@ -24,7 +24,4 @@ jobs: uses: ./.github/actions/setup - name: Format & Lint - run: turbo fmt-and-lint:ci - - - name: Run type checks - run: turbo types \ No newline at end of file + run: turbo fmt-and-lint:ci \ No newline at end of file diff --git a/.github/workflows/contracts-test-suite.yml b/.github/workflows/contracts-test-suite.yml index 86e003b1..ae20c870 100644 --- a/.github/workflows/contracts-test-suite.yml +++ b/.github/workflows/contracts-test-suite.yml @@ -115,5 +115,8 @@ jobs: echo -e "\nCompact code artifacts (src/artifacts):" find contracts -name "artifacts" -type d -exec ls -la {} \; + - name: Run type checks + run: turbo types + - name: Run Contract Tests run: turbo test \ No newline at end of file From b790aea73daa777f1e8865af354d94846f654b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 20:41:39 -0400 Subject: [PATCH 182/282] Add paths, update ubuntu version --- .github/workflows/checks.yml | 8 ++++---- .github/workflows/codeql.yml | 2 +- .github/workflows/contracts-test-suite.yml | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 36ace3e2..005fc33e 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -4,10 +4,10 @@ env: TURBO_TELEMETRY_DISABLED: 1 on: - push - # paths: - # - '**.ts' - # - '**.json' + push: + paths: + - '**.ts' + - '**.json' jobs: checks: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 99f20d31..a8a8d4b3 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -9,7 +9,7 @@ on: jobs: analyze: name: Analyze - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: github.event.repository.private == false timeout-minutes: 30 permissions: diff --git a/.github/workflows/contracts-test-suite.yml b/.github/workflows/contracts-test-suite.yml index ae20c870..1c89fc30 100644 --- a/.github/workflows/contracts-test-suite.yml +++ b/.github/workflows/contracts-test-suite.yml @@ -1,10 +1,10 @@ name: Compact Contracts Test Suite on: - push - # paths: - # - 'contracts/**/*.compact' - # - 'contracts/**/*.test.ts' + push: + paths: + - 'contracts/**/*.compact' + - 'contracts/**/*.ts' env: TURBO_TELEMETRY_DISABLED: 1 From 4f75e115aadd7da454ee7885d4eb1386986d741b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 21:33:47 -0400 Subject: [PATCH 183/282] Update action.yml --- .github/actions/setup/action.yml | 35 +++----------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 0da41aea..bc1d64a1 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -1,11 +1,5 @@ name: "Setup Environment" -description: "Sets up the environment with Compact compiler, yarn, and Node.js" - -inputs: - skip-compile: - description: "Skip the fast compile step" - required: false - default: "false" +description: "Sets up the environment with yarn, Node.js, and turbo" runs: using: "composite" @@ -22,7 +16,6 @@ runs: key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-yarn- - - name: Cache turbo build setup uses: actions/cache@v4 with: @@ -30,7 +23,6 @@ runs: key: ${{ runner.os }}-turbo-${{ hashFiles('.turbo/*') }}-${{ github.sha }} restore-keys: | ${{ runner.os }}-turbo-${{ hashFiles('.turbo/*') }} - - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -41,31 +33,10 @@ runs: shell: bash run: yarn install --immutable - - name: Build compact package + - name: Install Turbo Globally shell: bash env: TURBO_MAJOR_VERSION: 2 TURBO_TELEMETRY_DISABLED: 1 run: | - yarn build:compact - - - name: Validate build artifacts - shell: bash - run: | - REQUIRED_FILES=( - "compact/dist/runCompiler.js" - "compact/dist/runBuilder.js" - ) - for file in "${REQUIRED_FILES[@]}"; do - if [ ! -f "$file" ]; then - echo "::error::❌ Missing required file: $file" - exit 1 - fi - done - - - name: Fast compile contracts (skip zk) - env: - TURBO_TELEMETRY_DISABLED: 1 - if: ${{ inputs.skip-compile != 'true' }} - shell: bash - run: yarn compact -- --skip-zk + npm install turbo@${{ env.TURBO_MAJOR_VERSION }} -g From fcd9dc238914f9a4cadd964361236e4b9ae9a464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Fri, 13 Jun 2025 23:17:39 -0400 Subject: [PATCH 184/282] Rename erc721 package and files, update tsconfigs --- compact/tsconfig.json | 4 +- .../erc721/src/witnesses/ERC721Witnesses.ts | 31 - .../test/mocks/MockNonFungibleToken.compact} | 63 +- .../src/test/nonFungibleToken.test.ts | 1319 +++++++++++++++++ ...UninitializedNonFungibleTokenSimulator.ts} | 40 +- .../src/test/types/test.ts | 0 .../witnesses/NonFungibleTokenWitnesses.ts | 3 + .../{erc721 => nonFungibleToken}/turbo.json | 0 .../vitest.config.ts | 0 .../utils/src/test/Initializable.test.ts | 2 +- contracts/utils/src/test/Pausable.test.ts | 2 +- .../test/simulators/InitializableSimulator.ts | 4 +- .../src/test/simulators/PausableSimulator.ts | 4 +- .../src/test/simulators/UtilsSimulator.ts | 4 +- contracts/utils/src/test/utils.test.ts | 4 +- contracts/utils/src/test/utils/test.ts | 2 +- contracts/utils/tsconfig.json | 6 +- yarn.lock | 31 +- 18 files changed, 1403 insertions(+), 116 deletions(-) delete mode 100644 contracts/erc721/src/witnesses/ERC721Witnesses.ts rename contracts/{erc721/src/test/mocks/MockUninitializedERC721.compact => nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact} (66%) create mode 100644 contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts rename contracts/{erc721/src/test/simulators/ERC721UninitializedSimulator.ts => nonFungibleToken/src/test/simulators/UninitializedNonFungibleTokenSimulator.ts} (94%) rename contracts/{erc721 => nonFungibleToken}/src/test/types/test.ts (100%) create mode 100644 contracts/nonFungibleToken/src/witnesses/NonFungibleTokenWitnesses.ts rename contracts/{erc721 => nonFungibleToken}/turbo.json (100%) rename contracts/{erc721 => nonFungibleToken}/vitest.config.ts (100%) diff --git a/compact/tsconfig.json b/compact/tsconfig.json index 9c283308..145be791 100644 --- a/compact/tsconfig.json +++ b/compact/tsconfig.json @@ -3,13 +3,13 @@ "outDir": "dist", "rootDir": "src", "declaration": true, - "lib": ["es2023"], + "lib": ["es2022"], "module": "nodenext", "target": "es2022", "strict": true, "esModuleInterop": true, "skipLibCheck": true, - "moduleResolution": "node16", + "moduleResolution": "nodenext", "sourceMap": true, "rewriteRelativeImportExtensions": true, "erasableSyntaxOnly": true, diff --git a/contracts/erc721/src/witnesses/ERC721Witnesses.ts b/contracts/erc721/src/witnesses/ERC721Witnesses.ts deleted file mode 100644 index e3e7a723..00000000 --- a/contracts/erc721/src/witnesses/ERC721Witnesses.ts +++ /dev/null @@ -1,31 +0,0 @@ -<<<<<<< HEAD -import type * as Contract from "../artifacts/MockERC721/contract/index.cjs"; -import type { WitnessContext } from "@midnight-ntwrk/compact-runtime"; - -export type ERC721PrivateState = { - tokenURI: string; -}; - -export const ERC721Witnesses = { - /** - * @description A mock implementation of the computeTokenURI witness function - * - * @dev This function should be modified to meet the needs of your application - * - * @param {ERC721PrivateState} privateState The private state of the contract - * @param {string} baseURI The baseURI which is the empty string by default - * @returns {[ERC721PrivateState, string]} A tuple of the new private state and the declared return value - */ - computeTokenURI( - { privateState }: WitnessContext, - baseURI: string, - tokenId: bigint, - ): [ERC721PrivateState, string] { - return [privateState, baseURI + privateState.tokenURI + tokenId.toString()]; - }, -}; -======= -// This is how we type an empty object. -export type ERC721PrivateState = Record; -export const ERC721Witnesses = {}; ->>>>>>> 84243c7 (Update witness file) diff --git a/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact similarity index 66% rename from contracts/erc721/src/test/mocks/MockUninitializedERC721.compact rename to contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact index d23ab436..e49f236a 100644 --- a/contracts/erc721/src/test/mocks/MockUninitializedERC721.compact +++ b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact @@ -2,53 +2,60 @@ pragma language_version >= 0.15.0; import CompactStandardLibrary; -import "../../ERC721" prefix ERC721_; +import "../../NonFungibleToken" prefix NonFungibleToken_; export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; +constructor( + _name: Opaque<"string">, + _symbol: Opaque<"string"> +) { + NonFungibleToken_initialize(_name, _symbol); +} + export circuit name(): Opaque<"string"> { - return ERC721_name(); + return NonFungibleToken_name(); } export circuit symbol(): Opaque<"string"> { - return ERC721_symbol(); + return NonFungibleToken_symbol(); } export circuit balanceOf(account: Either): Uint<128> { - return ERC721_balanceOf(account); + return NonFungibleToken_balanceOf(account); } export circuit ownerOf(tokenId: Uint<128>): Either { - return ERC721_ownerOf(tokenId); + return NonFungibleToken_ownerOf(tokenId); } export circuit tokenURI(tokenId: Uint<128>): Opaque<"string"> { - return ERC721_tokenURI(tokenId); + return NonFungibleToken_tokenURI(tokenId); } export circuit approve( to: Either, tokenId: Uint<128> ): [] { - return ERC721_approve(to, tokenId); + return NonFungibleToken_approve(to, tokenId); } export circuit getApproved(tokenId: Uint<128>): Either { - return ERC721_getApproved(tokenId); + return NonFungibleToken_getApproved(tokenId); } export circuit setApprovalForAll( operator: Either, approved: Boolean ): [] { - return ERC721_setApprovalForAll(operator, approved); + return NonFungibleToken_setApprovalForAll(operator, approved); } export circuit isApprovedForAll( owner: Either, operator: Either ): Boolean { - return ERC721_isApprovedForAll(owner, operator); + return NonFungibleToken_isApprovedForAll(owner, operator); } export circuit transferFrom( @@ -56,15 +63,15 @@ export circuit transferFrom( to: Either, tokenId: Uint<128> ): [] { - return ERC721_transferFrom(from, to, tokenId); + return NonFungibleToken_transferFrom(from, to, tokenId); } export circuit _requireOwned(tokenId: Uint<128>): Either { - return ERC721__requireOwned(tokenId); + return NonFungibleToken__requireOwned(tokenId); } export circuit _ownerOf(tokenId: Uint<128>): Either { - return ERC721__ownerOf(tokenId); + return NonFungibleToken__ownerOf(tokenId); } export circuit _update( @@ -72,7 +79,7 @@ export circuit _update( tokenId: Uint<128>, auth: Either ): Either { - return ERC721__update(to, tokenId, auth); + return NonFungibleToken__update(to, tokenId, auth); } export circuit _approve( @@ -80,7 +87,7 @@ export circuit _approve( tokenId: Uint<128>, auth: Either ): [] { - return ERC721__approve(to, tokenId, auth); + return NonFungibleToken__approve(to, tokenId, auth); } export circuit _checkAuthorized( @@ -88,7 +95,7 @@ export circuit _checkAuthorized( spender: Either, tokenId: Uint<128> ): [] { - return ERC721__checkAuthorized(owner, spender, tokenId); + return NonFungibleToken__checkAuthorized(owner, spender, tokenId); } export circuit _isAuthorized( @@ -96,11 +103,11 @@ export circuit _isAuthorized( spender: Either, tokenId: Uint<128> ): Boolean { - return ERC721__isAuthorized(owner, spender, tokenId); + return NonFungibleToken__isAuthorized(owner, spender, tokenId); } export circuit _getApproved(tokenId: Uint<128>): Either { - return ERC721__getApproved(tokenId); + return NonFungibleToken__getApproved(tokenId); } export circuit _setApprovalForAll( @@ -108,18 +115,18 @@ export circuit _setApprovalForAll( operator: Either, approved: Boolean ): [] { - return ERC721__setApprovalForAll(owner, operator, approved); + return NonFungibleToken__setApprovalForAll(owner, operator, approved); } export circuit _mint( to: Either, tokenId: Uint<128> ): [] { - return ERC721__mint(to, tokenId); + return NonFungibleToken__mint(to, tokenId); } export circuit _burn(tokenId: Uint<128>): [] { - return ERC721__burn(tokenId); + return NonFungibleToken__burn(tokenId); } export circuit _transfer( @@ -127,11 +134,11 @@ export circuit _transfer( to: Either, tokenId: Uint<128> ): [] { - return ERC721__transfer(from, to, tokenId); + return NonFungibleToken__transfer(from, to, tokenId); } export circuit _setTokenURI(tokenId: Uint<128>, tokenURI: Opaque<"string">): [] { - return ERC721__setTokenURI(tokenId, tokenURI); + return NonFungibleToken__setTokenURI(tokenId, tokenURI); } export circuit _unsafeTransferFrom( @@ -139,20 +146,20 @@ export circuit _unsafeTransferFrom( to: Either, tokenId: Uint<128> ): [] { - return ERC721__unsafeTransferFrom(from, to, tokenId); + return NonFungibleToken__unsafeTransferFrom(from, to, tokenId); } -export circuit _unsafe_transfer( +export circuit _unsafeTransfer( from: Either, to: Either, tokenId: Uint<128> ): [] { - return ERC721__unsafe_transfer(from, to, tokenId); + return NonFungibleToken__unsafeTransfer(from, to, tokenId); } -export circuit _unsafe_mint( +export circuit _unsafeMint( to: Either, tokenId: Uint<128> ): [] { - return ERC721__unsafe_mint(to, tokenId); + return NonFungibleToken__unsafeMint(to, tokenId); } diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts new file mode 100644 index 00000000..c2edbc86 --- /dev/null +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -0,0 +1,1319 @@ +import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; +import { beforeEach, describe, expect, it } from 'vitest'; +import { NonFungibleTokenSimulator } from './simulators/NonFungibleTokenSimulator.js'; +import { UninitializedNonFungibleTokenSimulator } from './simulators/UninitializedNonFungibleTokenSimulator.js'; +import { + createEitherTestContractAddress, + createEitherTestUser, + ZERO_KEY, +} from './utils/address.js'; + +const SOME_STRING = 'https://openzeppelin.example'; + +const NAME = 'NAME'; +const SYMBOL = 'SYMBOL'; +const EMPTY_STRING = ''; + +const TOKENID: bigint = BigInt(1); +const AMOUNT: bigint = BigInt(1); + +const OWNER = String(Buffer.from('OWNER', 'ascii').toString('hex')).padStart( + 64, + '0', +); +const SPENDER = String( + Buffer.from('SPENDER', 'ascii').toString('hex'), +).padStart(64, '0'); +const UNAUTHORIZED = String( + Buffer.from('UNAUTHORIZED', 'ascii').toString('hex'), +).padStart(64, '0'); + +const Z_OWNER = createEitherTestUser('OWNER'); +const Z_SPENDER = createEitherTestUser('SPENDER'); +const Z_RECIPIENT = createEitherTestUser('RECIPIENT'); +const Z_OTHER = createEitherTestUser('OTHER'); +const SOME_CONTRACT = createEitherTestContractAddress('CONTRACT'); + +let token: NonFungibleTokenSimulator; +let _caller: CoinPublicKey; + +describe('NonFungibleToken', () => { + describe('initializer and metadata', () => { + it('should initialize metadata', () => { + token = new NonFungibleTokenSimulator(NAME, SYMBOL); + + expect(token.name()).toEqual(NAME); + expect(token.symbol()).toEqual(SYMBOL); + }); + + it('should initialize empty metadata', () => { + token = new NonFungibleTokenSimulator(EMPTY_STRING, EMPTY_STRING); + + expect(token.name()).toEqual(EMPTY_STRING); + expect(token.symbol()).toEqual(EMPTY_STRING); + }); + + it('should initialize metadata with whitespace', () => { + token = new NonFungibleTokenSimulator(' NAME ', ' SYMBOL '); + expect(token.name()).toEqual(' NAME '); + expect(token.symbol()).toEqual(' SYMBOL '); + }); + + it('should initialize metadata with special characters', () => { + token = new NonFungibleTokenSimulator('NAME!@#', 'SYMBOL$%^'); + expect(token.name()).toEqual('NAME!@#'); + expect(token.symbol()).toEqual('SYMBOL$%^'); + }); + + it('should initialize metadata with very long strings', () => { + const longName = 'A'.repeat(1000); + const longSymbol = 'B'.repeat(1000); + token = new NonFungibleTokenSimulator(longName, longSymbol); + expect(token.name()).toEqual(longName); + expect(token.symbol()).toEqual(longSymbol); + }); + }); + + beforeEach(() => { + token = new NonFungibleTokenSimulator(NAME, SYMBOL); + }); + + describe('balanceOf', () => { + it('should return zero when requested account has no balance', () => { + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + + it('should return balance when requested account has tokens', () => { + token._mint(Z_OWNER, AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + }); + + it('should return correct balance for multiple tokens', () => { + token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID + 1n); + token._mint(Z_OWNER, TOKENID + 2n); + expect(token.balanceOf(Z_OWNER)).toEqual(3n); + }); + + it('should return correct balance after burning multiple tokens', () => { + token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID + 1n); + token._mint(Z_OWNER, TOKENID + 2n); + token._burn(TOKENID); + token._burn(TOKENID + 1n); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + }); + + it('should return correct balance after transferring multiple tokens', () => { + token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID + 1n); + token._mint(Z_OWNER, TOKENID + 2n); + token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID); + token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID + 1n); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_SPENDER)).toEqual(2n); + }); + }); + + describe('ownerOf', () => { + it('should throw if tokenId does not exist', () => { + expect(() => { + token.ownerOf(TOKENID); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should throw if tokenId has been burned', () => { + token._mint(Z_OWNER, TOKENID); + token._burn(TOKENID); + expect(() => { + token.ownerOf(TOKENID); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should return owner of token if it exists', () => { + token._mint(Z_OWNER, TOKENID); + expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + }); + + it('should return correct owner for multiple tokens', () => { + token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID + 1n); + token._mint(Z_OWNER, TOKENID + 2n); + expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + expect(token.ownerOf(TOKENID + 1n)).toEqual(Z_OWNER); + expect(token.ownerOf(TOKENID + 2n)).toEqual(Z_OWNER); + }); + + it('should return correct owner after multiple transfers', () => { + token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID + 1n); + token._transfer(Z_OWNER, Z_SPENDER, TOKENID); + token._transfer(Z_OWNER, Z_OTHER, TOKENID + 1n); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID + 1n)).toEqual(Z_OTHER); + }); + + it('should return correct owner after multiple burns and mints', () => { + token._mint(Z_OWNER, TOKENID); + token._burn(TOKENID); + token._mint(Z_SPENDER, TOKENID); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + }); + }); + + describe('tokenURI', () => { + it('should throw if token does not exist', () => { + expect(() => { + token.tokenURI(TOKENID); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should return none if tokenURI set as default value', () => { + token._mint(Z_OWNER, TOKENID); + token._setTokenURI(TOKENID, EMPTY_STRING); + expect(token.tokenURI(TOKENID)).toEqual(EMPTY_STRING); + }); + + it('should return some string if tokenURI is set', () => { + token._mint(Z_OWNER, TOKENID); + token._setTokenURI(TOKENID, SOME_STRING); + expect(token.tokenURI(TOKENID)).toEqual(SOME_STRING); + }); + + it('should return empty string tokenURI', () => { + token._mint(Z_OWNER, TOKENID); + token._setTokenURI(TOKENID, ''); + expect(token.tokenURI(TOKENID)).toEqual(''); + }); + + it('should return very long tokenURI', () => { + const longURI = 'A'.repeat(1000); + token._mint(Z_OWNER, TOKENID); + token._setTokenURI(TOKENID, longURI); + expect(token.tokenURI(TOKENID)).toEqual(longURI); + }); + + it('should return tokenURI with special characters', () => { + const specialURI = '!@#$%^&*()_+'; + token._mint(Z_OWNER, TOKENID); + token._setTokenURI(TOKENID, specialURI); + expect(token.tokenURI(TOKENID)).toEqual(specialURI); + }); + + it('should update tokenURI multiple times', () => { + token._mint(Z_OWNER, TOKENID); + token._setTokenURI(TOKENID, 'URI1'); + token._setTokenURI(TOKENID, 'URI2'); + token._setTokenURI(TOKENID, 'URI3'); + expect(token.tokenURI(TOKENID)).toEqual('URI3'); + }); + + it('should maintain tokenURI after token transfer', () => { + token._mint(Z_OWNER, TOKENID); + token._setTokenURI(TOKENID, SOME_STRING); + token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID); + expect(token.tokenURI(TOKENID)).toEqual(SOME_STRING); + }); + }); + + describe('approve', () => { + beforeEach(() => { + token._mint(Z_OWNER, TOKENID); + expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + }); + + it('should throw if not owner', () => { + _caller = UNAUTHORIZED; + expect(() => { + token.approve(Z_SPENDER, TOKENID, _caller); + }).toThrow('NonFungibleToken: Invalid Approver'); + }); + + it('should approve spender', () => { + _caller = OWNER; + token.approve(Z_SPENDER, TOKENID, _caller); + expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + }); + + it('should allow operator to approve', () => { + _caller = OWNER; + token.setApprovalForAll(Z_SPENDER, true, _caller); + _caller = SPENDER; + token.approve(Z_OTHER, TOKENID, _caller); + expect(token.getApproved(TOKENID)).toEqual(Z_OTHER); + }); + + it('spender approved for only TOKENID should not be able to approve', () => { + _caller = OWNER; + token.approve(Z_SPENDER, TOKENID, _caller); + + _caller = SPENDER; + expect(() => { + token.approve(Z_OTHER, TOKENID, _caller); + }).toThrow('NonFungibleToken: Invalid Approver'); + }); + + it('should approve same address multiple times', () => { + _caller = OWNER; + token.approve(Z_SPENDER, TOKENID, _caller); + token.approve(Z_SPENDER, TOKENID, _caller); + expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + }); + + it('should approve after token transfer', () => { + _caller = OWNER; + token._transfer(Z_OWNER, Z_SPENDER, TOKENID); + + _caller = SPENDER; + token.approve(Z_OTHER, TOKENID, _caller); + expect(token.getApproved(TOKENID)).toEqual(Z_OTHER); + }); + + it('should approve after token burn and remint', () => { + _caller = OWNER; + token._burn(TOKENID); + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, _caller); + expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + }); + + it('should approve with very long token ID', () => { + _caller = OWNER; + const longTokenId = BigInt('18446744073709551615'); + token._mint(Z_OWNER, longTokenId); + token.approve(Z_SPENDER, longTokenId, _caller); + expect(token.getApproved(longTokenId)).toEqual(Z_SPENDER); + }); + }); + + describe('getApproved', () => { + it('should throw if tokenId does not exist', () => { + expect(() => { + token.getApproved(TOKENID); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should throw if tokenId has been burned', () => { + token._mint(Z_OWNER, TOKENID); + token._burn(TOKENID); + expect(() => { + token.getApproved(TOKENID); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should get current approved spender', () => { + token._mint(Z_OWNER, TOKENID); + token.approve(Z_OWNER, TOKENID); + expect(token.getApproved(TOKENID)).toEqual(Z_OWNER); + }); + + it('should return zero key if approval not set', () => { + token._mint(Z_OWNER, TOKENID); + expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + }); + }); + + describe('setApprovalForAll', () => { + it('should not approve zero address', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + expect(() => { + token.setApprovalForAll(ZERO_KEY, true, _caller); + }).toThrow('NonFungibleToken: Invalid Operator'); + }); + + it('should approve operator for all tokens', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + + token.setApprovalForAll(Z_SPENDER, true, OWNER); + expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); + }); + + it('spender should manage all tokens', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID + 1n); + token._mint(Z_OWNER, TOKENID + 2n); + + token.setApprovalForAll(Z_SPENDER, true, OWNER); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, SPENDER); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + + token.approve(Z_OTHER, TOKENID + 1n, SPENDER); + expect(token.getApproved(TOKENID + 1n)).toEqual(Z_OTHER); + + token.approve(Z_SPENDER, TOKENID + 2n, SPENDER); + expect(token.getApproved(TOKENID + 2n)).toEqual(Z_SPENDER); + }); + + it('should revoke approval for all', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.setApprovalForAll(Z_SPENDER, true, _caller); + expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); + + token.setApprovalForAll(Z_SPENDER, false, _caller); + expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(false); + + _caller = SPENDER; + expect(() => { + token.approve(Z_SPENDER, TOKENID, _caller); + }).toThrow('NonFungibleToken: Invalid Approver'); + }); + + it('should set approval for all to same address multiple times', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.setApprovalForAll(Z_SPENDER, true, _caller); + token.setApprovalForAll(Z_SPENDER, true, _caller); + expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); + }); + + it('should set approval for all after token transfer', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token._transfer(Z_OWNER, Z_SPENDER, TOKENID); + _caller = SPENDER; + token.setApprovalForAll(Z_OTHER, true, _caller); + expect(token.isApprovedForAll(Z_SPENDER, Z_OTHER)).toBe(true); + }); + + it('should set approval for all with multiple operators', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.setApprovalForAll(Z_SPENDER, true, _caller); + token.setApprovalForAll(Z_OTHER, true, _caller); + expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); + expect(token.isApprovedForAll(Z_OWNER, Z_OTHER)).toBe(true); + }); + + it('should set approval for all with very long token IDs', () => { + _caller = OWNER; + const longTokenId = BigInt('18446744073709551615'); + token._mint(Z_OWNER, longTokenId); + token.setApprovalForAll(Z_SPENDER, true, _caller); + expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); + }); + }); + + describe('isApprovedForAll', () => { + it('should return false if approval not set', () => { + expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(false); + }); + + it('should return true if approval set', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.setApprovalForAll(Z_SPENDER, true, OWNER); + expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); + }); + }); + + describe('transferFrom', () => { + it('should not transfer to ContractAddress', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token.transferFrom(Z_OWNER, SOME_CONTRACT, TOKENID); + }).toThrow('NonFungibleToken: Unsafe Transfer'); + }); + + it('should not transfer to zero address', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token.transferFrom(Z_OWNER, ZERO_KEY, TOKENID); + }).toThrow('NonFungibleToken: Invalid Receiver'); + }); + + it('should not transfer from zero address', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token.transferFrom(ZERO_KEY, Z_SPENDER, TOKENID); + }).toThrow('NonFungibleToken: Incorrect Owner'); + }); + + it('should not transfer from unauthorized', () => { + _caller = SPENDER; + token._mint(Z_OWNER, TOKENID); + expect(() => { + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + }).toThrow('NonFungibleToken: Insufficient Approval'); + }); + + it('should not transfer token that has not been minted', () => { + _caller = OWNER; + expect(() => { + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should transfer token via approved operator', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, OWNER); + + _caller = SPENDER; + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + }); + + it('should transfer token via approvedForAll operator', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.setApprovalForAll(Z_SPENDER, true, OWNER); + + _caller = SPENDER; + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + }); + + it('should allow transfer to same address', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + expect(() => { + token.transferFrom(Z_OWNER, Z_OWNER, TOKENID, _caller); + }).not.toThrow(); + expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + }); + + it('should not transfer after approval revocation', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, _caller); + token.approve(ZERO_KEY, TOKENID, _caller); + _caller = SPENDER; + expect(() => { + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + }).toThrow('NonFungibleToken: Insufficient Approval'); + }); + + it('should not transfer after approval for all revocation', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.setApprovalForAll(Z_SPENDER, true, _caller); + token.setApprovalForAll(Z_SPENDER, false, _caller); + _caller = SPENDER; + expect(() => { + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + }).toThrow('NonFungibleToken: Insufficient Approval'); + }); + + it('should transfer multiple tokens in sequence', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID + 1n); + token._mint(Z_OWNER, TOKENID + 2n); + token.approve(Z_SPENDER, TOKENID, _caller); + token.approve(Z_SPENDER, TOKENID + 1n, _caller); + token.approve(Z_SPENDER, TOKENID + 2n, _caller); + + _caller = SPENDER; + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID + 1n, _caller); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID + 2n, _caller); + + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID + 1n)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID + 2n)).toEqual(Z_SPENDER); + }); + + it('should transfer with very long token IDs', () => { + _caller = OWNER; + const longTokenId = BigInt('18446744073709551615'); + token._mint(Z_OWNER, longTokenId); + token.approve(Z_SPENDER, longTokenId, _caller); + + _caller = SPENDER; + token.transferFrom(Z_OWNER, Z_SPENDER, longTokenId, _caller); + expect(token.ownerOf(longTokenId)).toEqual(Z_SPENDER); + }); + + it('should revoke approval after transferFrom', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, _caller); + token.transferFrom(Z_OWNER, Z_OTHER, TOKENID, _caller); + expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + }); + }); + + describe('_requireOwned', () => { + it('should throw if token has not been minted', () => { + expect(() => { + token._requireOwned(TOKENID); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should throw if token has been burned', () => { + token._mint(Z_OWNER, TOKENID); + token._burn(TOKENID); + expect(() => { + token._requireOwned(TOKENID); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should return correct owner', () => { + token._mint(Z_OWNER, TOKENID); + expect(token._requireOwned(TOKENID)).toEqual(Z_OWNER); + }); + }); + + describe('_ownerOf', () => { + it('should return zero address if token does not exist', () => { + expect(token._ownerOf(TOKENID)).toEqual(ZERO_KEY); + }); + + it('should return owner of token', () => { + token._mint(Z_OWNER, TOKENID); + expect(token._ownerOf(TOKENID)).toEqual(Z_OWNER); + }); + }); + + describe('_update', () => { + it('should transfer token and clear approvals', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_OTHER, TOKENID, _caller); + const prevOwner = token._update(Z_SPENDER, TOKENID, ZERO_KEY); + + expect(prevOwner).toEqual(Z_OWNER); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_SPENDER)).toEqual(1n); + expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + }); + + it('should mint a token', () => { + const prevOwner = token._update(Z_OWNER, TOKENID, ZERO_KEY); + expect(prevOwner).toEqual(ZERO_KEY); + expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + }); + + it('should burn a token', () => { + token._mint(Z_OWNER, TOKENID); + const prevOwner = token._update(ZERO_KEY, TOKENID, Z_OWNER); + expect(prevOwner).toEqual(Z_OWNER); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token._ownerOf(TOKENID)).toEqual(ZERO_KEY); + }); + + it('should transfer if auth is authorized', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, _caller); + const prevOwner = token._update(Z_SPENDER, TOKENID, Z_SPENDER); + + expect(prevOwner).toEqual(Z_OWNER); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_SPENDER)).toEqual(1n); + }); + + it('should transfer if auth is authorized for all', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.setApprovalForAll(Z_SPENDER, true, _caller); + const prevOwner = token._update(Z_SPENDER, TOKENID, Z_SPENDER); + + expect(prevOwner).toEqual(Z_OWNER); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_SPENDER)).toEqual(1n); + }); + + it('should throw if auth is not authorized', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + expect(() => { + token._update(Z_SPENDER, TOKENID, Z_SPENDER); + }).toThrow('NonFungibleToken: Insufficient Approval'); + }); + + it('should update multiple tokens in sequence', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID + 1n); + token._mint(Z_OWNER, TOKENID + 2n); + token.approve(Z_SPENDER, TOKENID, _caller); + token.approve(Z_SPENDER, TOKENID + 1n, _caller); + token.approve(Z_SPENDER, TOKENID + 2n, _caller); + + token._update(Z_SPENDER, TOKENID, Z_SPENDER); + token._update(Z_SPENDER, TOKENID + 1n, Z_SPENDER); + token._update(Z_SPENDER, TOKENID + 2n, Z_SPENDER); + + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID + 1n)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID + 2n)).toEqual(Z_SPENDER); + }); + + it('should update with very long token IDs', () => { + _caller = OWNER; + const longTokenId = BigInt('18446744073709551615'); + token._mint(Z_OWNER, longTokenId); + token.approve(Z_SPENDER, longTokenId, _caller); + token._update(Z_SPENDER, longTokenId, Z_SPENDER); + expect(token.ownerOf(longTokenId)).toEqual(Z_SPENDER); + }); + + it('should update after multiple transfers', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token._transfer(Z_OWNER, Z_SPENDER, TOKENID); + _caller = SPENDER; + token.approve(Z_OTHER, TOKENID, _caller); + token._update(Z_OTHER, TOKENID, Z_OTHER); + expect(token.ownerOf(TOKENID)).toEqual(Z_OTHER); + }); + + it('should update after multiple burns', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token._burn(TOKENID); + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, _caller); + token._update(Z_SPENDER, TOKENID, Z_SPENDER); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + }); + }); + + describe('_approve', () => { + it('should approve if auth is owner', () => { + token._mint(Z_OWNER, TOKENID); + token._approve(Z_SPENDER, TOKENID, Z_OWNER); + expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + }); + + it('should approve if auth is approved for all', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.setApprovalForAll(Z_SPENDER, true, _caller); + token._approve(Z_SPENDER, TOKENID, Z_SPENDER); + expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + }); + + it('should throw if auth is unauthorized', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token._approve(Z_SPENDER, TOKENID, Z_SPENDER); + }).toThrow('NonFungibleToken: Invalid Approver'); + }); + + it('should approve if auth is zero address', () => { + token._mint(Z_OWNER, TOKENID); + token._approve(Z_SPENDER, TOKENID, ZERO_KEY); + expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + }); + }); + + describe('_checkAuthorized', () => { + it('should throw if token not minted', () => { + expect(() => { + token._checkAuthorized(ZERO_KEY, Z_OWNER, TOKENID); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should throw if spender does not have approval', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token._checkAuthorized(Z_OWNER, Z_SPENDER, TOKENID); + }).toThrow('NonFungibleToken: Insufficient Approval'); + }); + }); + + describe('_isAuthorized', () => { + it('should return true if spender is authorized', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, _caller); + expect(token._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID)).toBe(true); + }); + + it('should return true if spender is authorized for all', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.setApprovalForAll(Z_SPENDER, true, _caller); + expect(token._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID)).toBe(true); + }); + + it('should return true if spender is owner', () => { + token._mint(Z_OWNER, TOKENID); + expect(token._isAuthorized(Z_OWNER, Z_OWNER, TOKENID)).toBe(true); + }); + + it('should return false if spender is zero address', () => { + expect(token._isAuthorized(Z_OWNER, ZERO_KEY, TOKENID)).toBe(false); + }); + }); + + describe('_getApproved', () => { + it('should return zero address if token is not minted', () => { + expect(token._getApproved(TOKENID)).toEqual(ZERO_KEY); + }); + + it('should return approved address', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, _caller); + expect(token._getApproved(TOKENID)).toEqual(Z_SPENDER); + }); + }); + + describe('_setApprovalForAll', () => { + it('should approve operator', () => { + token._mint(Z_OWNER, TOKENID); + token._setApprovalForAll(Z_OWNER, Z_SPENDER, true); + expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); + }); + + it('should revoke operator approval', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.setApprovalForAll(Z_SPENDER, true, _caller); + expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); + + token._setApprovalForAll(Z_OWNER, Z_SPENDER, false); + expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(false); + }); + + it('should throw if operator is zero address', () => { + expect(() => { + token._setApprovalForAll(Z_OWNER, ZERO_KEY, true); + }).toThrow('NonFungibleToken: Invalid Operator'); + }); + }); + + describe('_mint', () => { + it('should not mint to ContractAddress', () => { + expect(() => { + token._mint(SOME_CONTRACT, TOKENID); + }).toThrow('NonFungibleToken: Unsafe Transfer'); + }); + + it('should not mint to zero address', () => { + expect(() => { + token._mint(ZERO_KEY, TOKENID); + }).toThrow('NonFungibleToken: Invalid Receiver'); + }); + + it('should not mint a token that already exists', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token._mint(Z_OWNER, TOKENID); + }).toThrow('NonFungibleToken: Invalid Sender'); + }); + + it('should mint token', () => { + token._mint(Z_OWNER, TOKENID); + expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + + token._mint(Z_OWNER, TOKENID + 1n); + token._mint(Z_OWNER, TOKENID + 2n); + expect(token.balanceOf(Z_OWNER)).toEqual(3n); + }); + + it('should mint multiple tokens in sequence', () => { + for (let i = 0; i < 10; i++) { + token._mint(Z_OWNER, TOKENID + BigInt(i)); + } + expect(token.balanceOf(Z_OWNER)).toEqual(10n); + }); + + it('should mint with very long token IDs', () => { + const longTokenId = BigInt('18446744073709551615'); + token._mint(Z_OWNER, longTokenId); + expect(token.ownerOf(longTokenId)).toEqual(Z_OWNER); + }); + + it('should mint after burning', () => { + token._mint(Z_OWNER, TOKENID); + token._burn(TOKENID); + token._mint(Z_OWNER, TOKENID); + expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + }); + + it('should mint with special characters in metadata', () => { + token._mint(Z_OWNER, TOKENID); + token._setTokenURI(TOKENID, '!@#$%^&*()_+'); + expect(token.tokenURI(TOKENID)).toEqual('!@#$%^&*()_+'); + }); + }); + + describe('_burn', () => { + it('should burn token', () => { + token._mint(Z_OWNER, TOKENID); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + + token._burn(TOKENID); + expect(token._ownerOf(TOKENID)).toEqual(ZERO_KEY); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + + it('should not burn a token that does not exist', () => { + expect(() => { + token._burn(TOKENID); + }).toThrow('NonFungibleToken: Invalid Sender'); + }); + + it('should clear approval when token is burned', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, _caller); + expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + + token._burn(TOKENID); + expect(token._getApproved(TOKENID)).toEqual(ZERO_KEY); + }); + + it('should burn multiple tokens in sequence', () => { + token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID + 1n); + token._mint(Z_OWNER, TOKENID + 2n); + token._burn(TOKENID); + token._burn(TOKENID + 1n); + token._burn(TOKENID + 2n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + + it('should burn with very long token IDs', () => { + const longTokenId = BigInt('18446744073709551615'); + token._mint(Z_OWNER, longTokenId); + token._burn(longTokenId); + expect(token._ownerOf(longTokenId)).toEqual(ZERO_KEY); + }); + + it('should burn after transfer', () => { + token._mint(Z_OWNER, TOKENID); + token._transfer(Z_OWNER, Z_SPENDER, TOKENID); + token._burn(TOKENID); + expect(token._ownerOf(TOKENID)).toEqual(ZERO_KEY); + }); + + it('should burn after approval', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, _caller); + token._burn(TOKENID); + expect(token._ownerOf(TOKENID)).toEqual(ZERO_KEY); + expect(token._getApproved(TOKENID)).toEqual(ZERO_KEY); + }); + }); + + describe('_transfer', () => { + it('should not transfer to ContractAddress', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token._transfer(Z_OWNER, SOME_CONTRACT, TOKENID); + }).toThrow('NonFungibleToken: Unsafe Transfer'); + }); + + it('should transfer token', () => { + token._mint(Z_OWNER, TOKENID); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_SPENDER)).toEqual(0n); + expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + + token._transfer(Z_OWNER, Z_SPENDER, TOKENID); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_SPENDER)).toEqual(1n); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + }); + + it('should not transfer to zero address', () => { + expect(() => { + token._transfer(Z_OWNER, ZERO_KEY, TOKENID); + }).toThrow('NonFungibleToken: Invalid Receiver'); + }); + + it('should throw if from does not own token', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token._transfer(Z_SPENDER, Z_SPENDER, TOKENID); + }).toThrow('NonFungibleToken: Incorrect Owner'); + }); + + it('should throw if token does not exist', () => { + expect(() => { + token._transfer(Z_OWNER, Z_SPENDER, TOKENID); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should revoke approval after _transfer', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, _caller); + token._transfer(Z_OWNER, Z_OTHER, TOKENID); + expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + }); + }); + + describe('_setTokenURI', () => { + it('should throw if token does not exist', () => { + expect(() => { + token._setTokenURI(TOKENID, EMPTY_STRING); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should set tokenURI', () => { + token._mint(Z_OWNER, TOKENID); + token._setTokenURI(TOKENID, SOME_STRING); + expect(token.tokenURI(TOKENID)).toEqual(SOME_STRING); + }); + }); + + describe('_unsafeMint', () => { + it('should mint to ContractAddress', () => { + expect(() => { + token._unsafeMint(SOME_CONTRACT, TOKENID); + }).not.toThrow(); + }); + + it('should not mint to zero address', () => { + expect(() => { + token._unsafeMint(ZERO_KEY, TOKENID); + }).toThrow('NonFungibleToken: Invalid Receiver'); + }); + + it('should not mint a token that already exists', () => { + token._unsafeMint(Z_OWNER, TOKENID); + expect(() => { + token._unsafeMint(Z_OWNER, TOKENID); + }).toThrow('NonFungibleToken: Invalid Sender'); + }); + + it('should mint token to public key', () => { + token._unsafeMint(Z_OWNER, TOKENID); + expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + + token._unsafeMint(Z_OWNER, TOKENID + 1n); + token._unsafeMint(Z_OWNER, TOKENID + 2n); + expect(token.balanceOf(Z_OWNER)).toEqual(3n); + }); + }); + + describe('_unsafeTransfer', () => { + it('should transfer to ContractAddress', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token._unsafeTransfer(Z_OWNER, SOME_CONTRACT, TOKENID); + }).not.toThrow(); + }); + + it('should transfer token to public key', () => { + token._mint(Z_OWNER, TOKENID); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_SPENDER)).toEqual(0n); + expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + + token._unsafeTransfer(Z_OWNER, Z_SPENDER, TOKENID); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_SPENDER)).toEqual(1n); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + }); + + it('should not transfer to zero address', () => { + expect(() => { + token._unsafeTransfer(Z_OWNER, ZERO_KEY, TOKENID); + }).toThrow('NonFungibleToken: Invalid Receiver'); + }); + + it('should throw if from does not own token', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token._unsafeTransfer(Z_SPENDER, Z_SPENDER, TOKENID); + }).toThrow('NonFungibleToken: Incorrect Owner'); + }); + + it('should throw if token does not exist', () => { + expect(() => { + token._unsafeTransfer(Z_OWNER, Z_SPENDER, TOKENID); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should revoke approval after _unsafeTransfer', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, _caller); + token._unsafeTransfer(Z_OWNER, Z_OTHER, TOKENID); + expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + }); + }); + + describe('_unsafeTransferFrom', () => { + it('should transfer to ContractAddress', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token._unsafeTransferFrom(Z_OWNER, SOME_CONTRACT, TOKENID); + }).not.toThrow(); + }); + + it('should not transfer to zero address', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token._unsafeTransferFrom(Z_OWNER, ZERO_KEY, TOKENID); + }).toThrow('NonFungibleToken: Invalid Receiver'); + }); + + it('should not transfer from zero address', () => { + token._mint(Z_OWNER, TOKENID); + expect(() => { + token._unsafeTransferFrom(ZERO_KEY, Z_SPENDER, TOKENID); + }).toThrow('NonFungibleToken: Incorrect Owner'); + }); + + it('unapproved operator should not transfer', () => { + _caller = SPENDER; + token._mint(Z_OWNER, TOKENID); + expect(() => { + token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + }).toThrow('NonFungibleToken: Insufficient Approval'); + }); + + it('should not transfer token that has not been minted', () => { + _caller = OWNER; + expect(() => { + token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + }).toThrow('NonFungibleToken: Nonexistent Token'); + }); + + it('should transfer token via approved operator', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, OWNER); + + _caller = SPENDER; + token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + }); + + it('should transfer token via approvedForAll operator', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.setApprovalForAll(Z_SPENDER, true, OWNER); + + _caller = SPENDER; + token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + }); + + it('should revoke approval after _unsafeTransferFrom', () => { + _caller = OWNER; + token._mint(Z_OWNER, TOKENID); + token.approve(Z_SPENDER, TOKENID, _caller); + token._unsafeTransferFrom(Z_OWNER, Z_OTHER, TOKENID, _caller); + expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + }); + }); +}); + +let uninitializedToken: UninitializedNonFungibleTokenSimulator; + +describe('Uninitialized NonFungibleToken', () => { + beforeEach(() => { + uninitializedToken = new UninitializedNonFungibleTokenSimulator(); + }); + + describe('name', () => { + it('should throw', () => { + expect(() => { + uninitializedToken.name(); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('symbol', () => { + it('should throw', () => { + expect(() => { + uninitializedToken.symbol(); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('balanceOf', () => { + it('should throw', () => { + expect(() => { + uninitializedToken.balanceOf(Z_OWNER); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('ownerOf', () => { + it('should throw', () => { + expect(() => { + uninitializedToken.ownerOf(TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('tokenURI', () => { + it('should throw', () => { + expect(() => { + uninitializedToken.tokenURI(TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('approve', () => { + it('should throw', () => { + expect(() => { + uninitializedToken.approve(Z_OWNER, TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('getApproved', () => { + it('should throw', () => { + expect(() => { + uninitializedToken.getApproved(TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('setApprovalForAll', () => { + it('should throw', () => { + expect(() => { + uninitializedToken.setApprovalForAll(Z_OWNER, true); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('isApprovedForAll', () => { + it('should throw', () => { + expect(() => { + uninitializedToken.isApprovedForAll(Z_OWNER, Z_SPENDER); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('transferFrom', () => { + it('should throw', () => { + expect(() => { + uninitializedToken.transferFrom(Z_OWNER, Z_SPENDER, TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_requireOwned', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._requireOwned(TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_ownerOf', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._ownerOf(TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_update', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._update(Z_OWNER, TOKENID, Z_SPENDER); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_approve', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._approve(Z_OWNER, TOKENID, Z_SPENDER); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_checkAuthorized', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._checkAuthorized(Z_OWNER, Z_SPENDER, TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_isAuthorized', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_getApproved', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._getApproved(TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_setApprovalForAll', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._setApprovalForAll(Z_OWNER, Z_SPENDER, true); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_mint', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._mint(Z_OWNER, TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_burn', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._burn(TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_transfer', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._transfer(Z_OWNER, Z_SPENDER, TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_setTokenURI', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._setTokenURI(TOKENID, SOME_STRING); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_unsafeTransferFrom', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_unsafeTransfer', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._unsafeTransfer(Z_OWNER, Z_SPENDER, TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('_unsafeMint', () => { + it('should throw', () => { + expect(() => { + uninitializedToken._unsafeMint(Z_OWNER, TOKENID); + }).toThrow('Initializable: contract not initialized'); + }); + }); +}); diff --git a/contracts/erc721/src/test/simulators/ERC721UninitializedSimulator.ts b/contracts/nonFungibleToken/src/test/simulators/UninitializedNonFungibleTokenSimulator.ts similarity index 94% rename from contracts/erc721/src/test/simulators/ERC721UninitializedSimulator.ts rename to contracts/nonFungibleToken/src/test/simulators/UninitializedNonFungibleTokenSimulator.ts index a89aa5df..f4761427 100644 --- a/contracts/erc721/src/test/simulators/ERC721UninitializedSimulator.ts +++ b/contracts/nonFungibleToken/src/test/simulators/UninitializedNonFungibleTokenSimulator.ts @@ -12,38 +12,38 @@ import { type Either, type ZswapCoinPublicKey, type ContractAddress, - Contract as MockUninitializedERC721, + Contract as MockUninitializedNonFungibleToken, ledger, -} from '../../artifacts/MockUninitializedERC721/contract/index.cjs'; // Combined imports +} from '../../artifacts/MockUninitializedNonFungibleToken/contract/index.cjs'; // Combined imports import { - type ERC721PrivateState, - ERC721Witnesses, -} from '../../witnesses/ERC721Witnesses'; -import type { IContractSimulator } from '../types/test'; + type NonFungibleTokenPrivateState, + NonFungibleTokenWitnesses, +} from '../../witnesses/NonFungibleTokenWitnesses.js'; +import type { IContractSimulator } from '../types/test.js'; /** - * @description A simulator implementation of an ERC721 contract for testing purposes. - * @template P - The private state type, fixed to ERC721PrivateState. + * @description A simulator implementation of an NonFungibleToken contract for testing purposes. + * @template P - The private state type, fixed to NonFungibleTokenPrivateState. * @template L - The ledger type, fixed to Contract.Ledger. */ -export class ERC721UninitializedSimulator - implements IContractSimulator +export class UninitializedNonFungibleTokenSimulator + implements IContractSimulator { /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockUninitializedERC721; + readonly contract: MockUninitializedNonFungibleToken; /** @description The deployed address of the contract. */ readonly contractAddress: string; /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; + circuitContext: CircuitContext; /** * @description Initializes the mock contract. */ constructor() { - this.contract = new MockUninitializedERC721( - ERC721Witnesses, + this.contract = new MockUninitializedNonFungibleToken( + NonFungibleTokenWitnesses, ); const { currentPrivateState, @@ -72,9 +72,9 @@ export class ERC721UninitializedSimulator /** * @description Retrieves the current private state of the contract. - * @returns The private state of type ERC721PrivateState. + * @returns The private state of type NonFungibleTokenPrivateState. */ - public getCurrentPrivateState(): ERC721PrivateState { + public getCurrentPrivateState(): NonFungibleTokenPrivateState { return this.circuitContext.currentPrivateState; } @@ -592,12 +592,12 @@ export class ERC721UninitializedSimulator * @param {TokenId} tokenId - The token to transfer * @return {[]} - None. */ - public _unsafe_transfer( + public _unsafeTransfer( from: Either, to: Either, tokenId: bigint, ) { - this.circuitContext = this.contract.impureCircuits._unsafe_transfer( + this.circuitContext = this.contract.impureCircuits._unsafeTransfer( this.circuitContext, from, to, @@ -621,11 +621,11 @@ export class ERC721UninitializedSimulator * @param {TokenId} tokenId - The token to transfer * @return {[]} - None. */ - public _unsafe_mint( + public _unsafeMint( to: Either, tokenId: bigint, ) { - this.circuitContext = this.contract.impureCircuits._unsafe_mint( + this.circuitContext = this.contract.impureCircuits._unsafeMint( this.circuitContext, to, tokenId, diff --git a/contracts/erc721/src/test/types/test.ts b/contracts/nonFungibleToken/src/test/types/test.ts similarity index 100% rename from contracts/erc721/src/test/types/test.ts rename to contracts/nonFungibleToken/src/test/types/test.ts diff --git a/contracts/nonFungibleToken/src/witnesses/NonFungibleTokenWitnesses.ts b/contracts/nonFungibleToken/src/witnesses/NonFungibleTokenWitnesses.ts new file mode 100644 index 00000000..4ff84e7f --- /dev/null +++ b/contracts/nonFungibleToken/src/witnesses/NonFungibleTokenWitnesses.ts @@ -0,0 +1,3 @@ +// This is how we type an empty object. +export type NonFungibleTokenPrivateState = Record; +export const NonFungibleTokenWitnesses = {}; diff --git a/contracts/erc721/turbo.json b/contracts/nonFungibleToken/turbo.json similarity index 100% rename from contracts/erc721/turbo.json rename to contracts/nonFungibleToken/turbo.json diff --git a/contracts/erc721/vitest.config.ts b/contracts/nonFungibleToken/vitest.config.ts similarity index 100% rename from contracts/erc721/vitest.config.ts rename to contracts/nonFungibleToken/vitest.config.ts diff --git a/contracts/utils/src/test/Initializable.test.ts b/contracts/utils/src/test/Initializable.test.ts index 125d253b..a3bb2eba 100644 --- a/contracts/utils/src/test/Initializable.test.ts +++ b/contracts/utils/src/test/Initializable.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, expect, it } from 'vitest'; -import { InitializableSimulator } from './simulators/InitializableSimulator'; +import { InitializableSimulator } from './simulators/InitializableSimulator.js'; let initializable: InitializableSimulator; diff --git a/contracts/utils/src/test/Pausable.test.ts b/contracts/utils/src/test/Pausable.test.ts index 0a16e444..94662b0c 100644 --- a/contracts/utils/src/test/Pausable.test.ts +++ b/contracts/utils/src/test/Pausable.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, expect, it } from 'vitest'; -import { PausableSimulator } from './simulators/PausableSimulator'; +import { PausableSimulator } from './simulators/PausableSimulator.js'; let pausable: PausableSimulator; diff --git a/contracts/utils/src/test/simulators/InitializableSimulator.ts b/contracts/utils/src/test/simulators/InitializableSimulator.ts index fa8ad2f2..e2cfa376 100644 --- a/contracts/utils/src/test/simulators/InitializableSimulator.ts +++ b/contracts/utils/src/test/simulators/InitializableSimulator.ts @@ -13,8 +13,8 @@ import { import { type InitializablePrivateState, InitializableWitnesses, -} from '../../witnesses/InitializableWitnesses'; -import type { IContractSimulator } from '../types/test'; +} from '../../witnesses/InitializableWitnesses.js'; +import type { IContractSimulator } from '../types/test.js'; /** * @description A simulator implementation of an utils contract for testing purposes. diff --git a/contracts/utils/src/test/simulators/PausableSimulator.ts b/contracts/utils/src/test/simulators/PausableSimulator.ts index 034d84a4..cbec7204 100644 --- a/contracts/utils/src/test/simulators/PausableSimulator.ts +++ b/contracts/utils/src/test/simulators/PausableSimulator.ts @@ -13,8 +13,8 @@ import { import { type PausablePrivateState, PausableWitnesses, -} from '../../witnesses/PausableWitnesses'; -import type { IContractSimulator } from '../types/test'; +} from '../../witnesses/PausableWitnesses.js'; +import type { IContractSimulator } from '../types/test.js'; /** * @description A simulator implementation of an utils contract for testing purposes. diff --git a/contracts/utils/src/test/simulators/UtilsSimulator.ts b/contracts/utils/src/test/simulators/UtilsSimulator.ts index 6b7618cb..5b204e2d 100644 --- a/contracts/utils/src/test/simulators/UtilsSimulator.ts +++ b/contracts/utils/src/test/simulators/UtilsSimulator.ts @@ -16,8 +16,8 @@ import { import { type UtilsPrivateState, UtilsWitnesses, -} from '../../witnesses/UtilsWitnesses'; -import type { IContractSimulator } from '../types/test'; +} from '../../witnesses/UtilsWitnesses.js'; +import type { IContractSimulator } from '../types/test.js'; /** * @description A simulator implementation of an utils contract for testing purposes. diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 41772fef..1e415546 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { UtilsSimulator } from './simulators/UtilsSimulator'; -import * as contractUtils from './utils/address'; +import { UtilsSimulator } from './simulators/UtilsSimulator.js'; +import * as contractUtils from './utils/address.js'; const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); diff --git a/contracts/utils/src/test/utils/test.ts b/contracts/utils/src/test/utils/test.ts index d467e572..9fd2d4f6 100644 --- a/contracts/utils/src/test/utils/test.ts +++ b/contracts/utils/src/test/utils/test.ts @@ -6,7 +6,7 @@ import { QueryContext, emptyZswapLocalState, } from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types/test'; +import type { IContractSimulator } from '../types/test.js'; /** * Constructs a `CircuitContext` from the given state and sender information. diff --git a/contracts/utils/tsconfig.json b/contracts/utils/tsconfig.json index a6b072c2..0ff1d3e9 100644 --- a/contracts/utils/tsconfig.json +++ b/contracts/utils/tsconfig.json @@ -4,10 +4,10 @@ "rootDir": "src", "outDir": "dist", "declaration": true, - "lib": ["ESNext"], + "lib": ["ES2022"], "target": "ES2022", - "module": "ESNext", - "moduleResolution": "node16", + "module": "nodenext", + "moduleResolution": "nodenext", "allowJs": true, "forceConsistentCasingInFileNames": true, "noImplicitAny": true, diff --git a/yarn.lock b/yarn.lock index c6ad338b..344bcd1c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -392,7 +392,7 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/compact@workspace:compact" dependencies: - "@types/node": "npm:22.14.0" + "@types/node": "npm:^22.14.0" chalk: "npm:^5.4.1" fast-check: "npm:^3.15.0" log-symbols: "npm:^7.0.0" @@ -407,35 +407,23 @@ __metadata: "@openzeppelin-midnight/erc20@workspace:contracts/erc20": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/erc20@workspace:contracts/erc20" - dependencies: - "@openzeppelin-midnight/compact": "workspace:^" - "@types/node": "npm:^18.18.6" - ts-node: "npm:^10.9.2" - typescript: "npm:^5.2.2" - vitest: "npm:^3.1.3" - languageName: unknown - linkType: soft - -"@openzeppelin-midnight/erc721@workspace:contracts/erc721": - version: 0.0.0-use.local - resolution: "@openzeppelin-midnight/erc721@workspace:contracts/erc721" dependencies: "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" - "@types/node": "npm:^18.18.6" + "@types/node": "npm:^22.14.0" ts-node: "npm:^10.9.2" typescript: "npm:^5.2.2" vitest: "npm:^3.1.3" languageName: unknown linkType: soft -"@openzeppelin-midnight/erc721@workspace:contracts/erc721": +"@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken": version: 0.0.0-use.local - resolution: "@openzeppelin-midnight/erc721@workspace:contracts/erc721" + resolution: "@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken" dependencies: "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" - "@types/node": "npm:^18.18.6" + "@types/node": "npm:^22.14.0" ts-node: "npm:^10.9.2" typescript: "npm:^5.2.2" vitest: "npm:^3.1.3" @@ -446,6 +434,7 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" dependencies: + "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:^18.18.6" ts-node: "npm:^10.9.2" @@ -664,12 +653,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^22.13.10": - version: 22.15.2 - resolution: "@types/node@npm:22.15.2" +"@types/node@npm:^22.14.0": + version: 22.15.21 + resolution: "@types/node@npm:22.15.21" dependencies: undici-types: "npm:~6.21.0" - checksum: 10/e22071571205413518aa3710644ed9603d8f4a417fc59f0e180240e1c05aaf7fb8feecdf553a2da305247b3533d03b58eab6e333115f01f581b9139a6b1dcd47 + checksum: 10/cb4189587cca445bfb8166c0ed39f9344d743f37f3da892f2999a99bbabda45dc773237e61ecb7d1dc83dd95718cb1b5715b0be5dd7953565b19019e36a7cf39 languageName: node linkType: hard From 769b9a4097e4e289b88febe85a324730c3231422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 14:49:56 -0400 Subject: [PATCH 185/282] Add C2C Migration Plan to Module Docs --- .../src/nonFungibleToken.compact | 635 ++++++++++++++++++ 1 file changed, 635 insertions(+) create mode 100644 contracts/nonFungibleToken/src/nonFungibleToken.compact diff --git a/contracts/nonFungibleToken/src/nonFungibleToken.compact b/contracts/nonFungibleToken/src/nonFungibleToken.compact new file mode 100644 index 00000000..7a78621d --- /dev/null +++ b/contracts/nonFungibleToken/src/nonFungibleToken.compact @@ -0,0 +1,635 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.15.0; + +/** + * @module NonFungibleToken + * @description An unshielded Non-Fungible Token library. + * + * @notice One notable difference regarding this implementation and the EIP20 spec + * consists of the token size. Uint<128> is used as the token size because Uint<256> + * cannot be supported. + * This is due to encoding limits on the midnight circuit backend: + * https://github.com/midnightntwrk/compactc/issues/929 + * + * @notice At the moment Midnight does not support contract-to-contract communication, but + * there are ongoing efforts to enable this in the future. Thus, the main circuits of this module + * restrict developers from sending tokens to contracts; however, we provide developers + * the ability to experiment with sending tokens to contracts using the `_unsafe` + * transfer methods. Once contract-to-contract communication is available we will follow the + * deprecation plan outlined below: + * + * Initial Minor Version Change: + * + * - Mark _unsafeTransfer as deprecated and emit a warning if possible. + * - Keep its implementation intact so existing callers continue to work. + * + * Later Major Version Change: + * + * - Drop _unsafeTransfer and remove `isContract` guard from `transfer`. + * - By this point, anyone using _unsafeTransfer should have migrated to the now C2C-capable `transfer`. + * + * @notice TODO List - Missing Features and Improvements: + * @notice TODO: Support Uint256 token IDs + * @notice TODO: Implement Transfer/Approval events + * @notice TODO: Add safe transfer functions + * @notice TODO: Add _baseURI() support + * @notice TODO: Add ERC165 support + */ + +module NonFungibleToken { + import CompactStandardLibrary; + import "../../node_modules/@openzeppelin-midnight/utils/src/Utils" prefix Utils_; + import "../../node_modules/@openzeppelin-midnight/utils/src/Initializable" prefix Initializable_; + + /// Public state + export sealed ledger _name: Opaque<"string">; + export sealed ledger _symbol: Opaque<"string">; + export ledger _owners: Map, Either>; + export ledger _balances: Map, Uint<128>>; + export ledger _tokenApprovals: Map, Either>; + export ledger _operatorApprovals: Map, Map, Boolean>>; + export ledger _tokenURIs: Map, Opaque<"string">>; + + /** + * @description Initializes the contract by setting the name and symbol. + * + * @param {Opaque<"string">} name_ - The name of the token. + * @param {Opaque<"string">} symbol_ - The symbol of the token. + * @return {[]} - None. + */ + export circuit initialize( + name_: Opaque<"string">, + symbol_: Opaque<"string"> + ): [] { + Initializable_initialize(); + _name = name_; + _symbol = symbol_; + } + + /** + * @description Returns the number of tokens in `owner`'s account. + * + * @param {Either)} owner - The account to query. + * @return {Uint<128>} - The number of tokens in `owner`'s account. + */ + export circuit balanceOf(owner: Either): Uint<128> { + Initializable_assertInitialized(); + if (!_balances.member(owner)) { + return 0; + } + + return _balances.lookup(owner); + } + + /** + * @description Returns the owner of the `tokenId` token. + * + * @param {Uint<128>} tokenId - The identifier for a token. + * @return {Either} - The account that owns the token. + */ + export circuit ownerOf(tokenId: Uint<128>): Either { + Initializable_assertInitialized(); + return _requireOwned(tokenId); + } + + /** + * @description Returns the token name. + * + * @return {Opaque<"string">} - The token name. + */ + export circuit name(): Opaque<"string"> { + Initializable_assertInitialized(); + return _name; + } + + /** + * @description Returns the symbol of the token. + * + * @return {Opaque<"string">} - The token symbol. + */ + export circuit symbol(): Opaque<"string"> { + Initializable_assertInitialized(); + return _symbol; + } + + /** + * @description Returns the token URI for the given `tokenId`. + * + * @notice Midnight does not support native strings and string operations + * within the Compact language, e.g. concatenating a base URI + token ID are not possible + * like in other NFT implementations. Therefore, we propose the URI storage + * approach; whereby, NFTs may or may not have unique "base" URIs. + * It's up to the implementation to decide on how to handle this. + * + * @param {Uint<128>} tokenId - The identifier for a token. + * @returns {Opaque<"string">} - the token id's URI. + */ + export circuit tokenURI(tokenId: Uint<128>): Opaque<"string"> { + Initializable_assertInitialized(); + _requireOwned(tokenId); + + return _tokenURIs.lookup(tokenId); + } + + /** + * @description Sets the the URI as `tokenURI` for the given `tokenId`. + * The `tokenId` must exist. + * + * @notice The URI for a given NFT is usually set when the NFT is minted. + * + * @param {Uint<128>} tokenId - The identifier of the token. + * @param {Opaque<"string">} tokenURI - The URI of `tokenId`. + * @return {[]} - None. + */ + export circuit _setTokenURI(tokenId: Uint<128>, tokenURI: Opaque<"string">): [] { + Initializable_assertInitialized(); + _requireOwned(tokenId); + + return _tokenURIs.insert(tokenId, tokenURI); + } + + /** + * @description Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must either own the token or be an approved operator. + * - `tokenId` must exist. + * + * @param {Either} to - The account receiving the approval + * @param {Uint<128>} tokenId - The token `to` may be permitted to transfer + * @return {[]} - None. + */ + export circuit approve( + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + const auth = left(own_public_key()); + _approve( + to, + tokenId, + auth + ); + } + + /** + * @description Returns the account approved for `tokenId` token. + * @param {Uint<128>} tokenId - The token an account may be approved to manage + * @return {Either} Operator- The account approved to manage the token + */ + export circuit getApproved(tokenId: Uint<128>): Either { + Initializable_assertInitialized(); + _requireOwned(tokenId); + + return _getApproved(tokenId); + } + + /** + * @description Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the address zero. + * + * @param {Either} operator - An operator to manage the caller's tokens + * @param {Boolean} approved - A boolean determining if `operator` may manage all tokens of the caller + * @return {[]} - None. + */ + export circuit setApprovalForAll( + operator: Either, + approved: Boolean + ): [] { + Initializable_assertInitialized(); + const owner = left(own_public_key()); + _setApprovalForAll( + owner, + operator, + approved + ); + } + + /** + * @description Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * @param {Either} owner - The owner of a token + * @param {Either} operator - An account that may operate on `owner`'s tokens + * @return {Boolean} - A boolean determining if `operator` is allowed to manage all of the tokens of `owner` + */ + export circuit isApprovedForAll( + owner: Either, + operator: Either + ): Boolean { + Initializable_assertInitialized(); + if (_operatorApprovals.member(owner) && _operatorApprovals.lookup(owner).member(operator)) { + return _operatorApprovals.lookup(owner).lookup(operator); + } else { + return false; + } + } + + /** + * @description Transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address or a ContractAddress. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * @param {Either} from - The source account from which the token is being transfered + * @param {Either} to - The target account to transfer token to + * @param {Uint<128>} tokenId - The token being transfered + * @return {[]} - None. + */ + export circuit transferFrom( + from: Either, + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; + assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; + // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists + // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. + const auth = left(own_public_key()); + const previousOwner = _update( + to, + tokenId, + auth + ); + assert previousOwner == from "NonFungibleToken: Incorrect Owner"; + } + + /** + * @description Transfers `tokenId` token from `from` to `to`. It does NOT check if the recipient is a ContractAddress. + * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the + * ContractAddress + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * @param {Either} from - The source account from which the token is being transfered + * @param {Either} to - The target account to transfer token to + * @param {Uint<128>} tokenId - The token being transfered + * @return {[]} - None. + */ + export circuit _unsafeTransferFrom( + from: Either, + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; + // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists + // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. + const auth = left(own_public_key()); + const previousOwner = _update( + to, + tokenId, + auth + ); + assert previousOwner == from "NonFungibleToken: Incorrect Owner"; + } + + /** + * @description Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist + * + * @param {Uint<128>} tokenId - The target token of the owner query + * @return {Either} - The owner of the token + */ + export circuit _ownerOf(tokenId: Uint<128>): Either { + Initializable_assertInitialized(); + if (!_owners.member(tokenId)) { + return burn_address(); + } + + return _owners.lookup(tokenId); + } + + /** + * @description Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. + * + * @param {Uint<128>} tokenId - The token to query + * @return {Either} - An account approved to spend `tokenId` + */ + export circuit _getApproved(tokenId: Uint<128>): Either { + Initializable_assertInitialized(); + if (!_tokenApprovals.member(tokenId)) { + return burn_address(); + } + return _tokenApprovals.lookup(tokenId); + } + + /** + * @description Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in + * particular (ignoring whether it is owned by `owner`). + * + * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this + * assumption. + * + * @param {Either} owner - Owner of the token + * @param {Either} spender - Account that wishes to spend `tokenId` + * @param {Uint<128>} tokenId - Token to spend + * @return {Boolean} - A boolean determining if `spender` may manage `tokenId` + */ + export circuit _isAuthorized( + owner: Either, + spender: Either, + tokenId: Uint<128> + ): Boolean { + Initializable_assertInitialized(); + return ( + !Utils_isKeyOrAddressZero(spender) && + (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender) + ); + } + + /** + * @description Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. + * Reverts if: + * - `spender` does not have approval from `owner` for `tokenId`. + * - `spender` does not have approval to manage all of `owner`'s assets. + * + * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this + * assumption. + * + * @param {Either} owner - Owner of the token + * @param {Either} spender - Account operating on `tokenId` + * @param {Uint<128>} tokenId - The token to spend + * @return {[]} - None. + */ + export circuit _checkAuthorized( + owner: Either, + spender: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + if (!_isAuthorized(owner, spender, tokenId)) { + assert !Utils_isKeyOrAddressZero(owner) "NonFungibleToken: Nonexistent Token"; + assert false "NonFungibleToken: Insufficient Approval"; + } + } + + /** + * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner + * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. + * + * The `auth` argument is optional. If the value passed is non 0, then this function will check that + * `auth` is either the owner of the token, or approved to operate on the token (by the owner). + * + * @param {Either} to - The intended recipient of the token transfer + * @param {Uint<128>} tokenId - The token being transfered + * @param {Either} auth - An account authorized to transfer the token + * @return {Either} - Owner of the token before it was transfered + */ + export circuit _update( + to: Either, + tokenId: Uint<128>, + auth: Either + ): Either { + Initializable_assertInitialized(); + const from = _ownerOf(tokenId); + + // Perform (optional) operator check + if (!Utils_isKeyOrAddressZero(auth)) { + _checkAuthorized(from, auth, tokenId); + } + + // Execute the update + if (!Utils_isKeyOrAddressZero(from)) { + // Clear approval. No need to re-authorize + _approve(burn_address(), tokenId, burn_address()); + const newBalance = _balances.lookup(from) - 1 as Uint<128>; + _balances.insert(from, newBalance); + } + + if (!Utils_isKeyOrAddressZero(to)) { + if (!_balances.member(to)) { + _balances.insert(to, 0); + } + const newBalance = _balances.lookup(to) + 1 as Uint<128>; + _balances.insert(to, newBalance); + } + + _owners.insert(tokenId, to); + + return from; + } + + /** + * @description Mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address or a ContractAddress. + * + * @param {Either} to - The account receiving `tokenId` + * @param {Uint<128>} tokenId - The token to transfer + * @return {[]} - None. + */ + export circuit _mint( + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; + assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; + + const previousOwner = _update(to, tokenId, burn_address()); + + assert Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Invalid Sender"; + } + + /** + * @description Mints `tokenId` and transfers it to `to`. It does NOT check if the recipient is a ContractAddress. + * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * @param {Either} to - The account receiving `tokenId` + * @param {Uint<128>} tokenId - The token to transfer + * @return {[]} - None. + */ + export circuit _unsafeMint( + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; + + const previousOwner = _update(to, tokenId, burn_address()); + + assert Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Invalid Sender"; + } + + /** + * @description Destroys `tokenId`. + * The approval is cleared when the token is burned. + * This circuit does not check if the sender is authorized to operate on the token. + * + * Requirements: + * + * - `tokenId` must exist. + * + * @param {Uint<128>} tokenId - The token to burn + * @return {[]} - None. + */ + export circuit _burn(tokenId: Uint<128>): [] { + Initializable_assertInitialized(); + const previousOwner = _update(burn_address(), tokenId, burn_address()); + assert !Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Invalid Sender"; + } + + /** + * @description Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on own_public_key(). + * + * Requirements: + * + * - `to` cannot be the zero address or a ContractAddress. + * - `tokenId` token must be owned by `from`. + * + * @param {Either} from - The source account of the token transfer + * @param {Either} to - The target account of the token transfer + * @param {Uint<128>} tokenId - The token to transfer + * @return {[]} - None. + */ + export circuit _transfer( + from: Either, + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; + assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; + + const previousOwner = _update(to, tokenId, burn_address()); + + assert !Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Nonexistent Token"; + assert previousOwner == from "NonFungibleToken: Incorrect Owner"; + } + + /** + * @description Transfers `tokenId` from `from` to `to`. + * As opposed to {_unsafeTransferFrom}, this imposes no restrictions on own_public_key(). + * It does NOT check if the recipient is a ContractAddress. + * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the + * ContractAddress + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * @param {Either} from - The source account of the token transfer + * @param {Either} to - The target account of the token transfer + * @param {Uint<128>} tokenId - The token to transfer + * @return {[]} - None. + */ + export circuit _unsafeTransfer( + from: Either, + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; + + const previousOwner = _update(to, tokenId, burn_address()); + + assert !Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Nonexistent Token"; + assert previousOwner == from "NonFungibleToken: Incorrect Owner"; + } + + /** + * @description Approve `to` to operate on `tokenId` + * + * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is + * either the owner of the token, or approved to operate on all tokens held by this owner. + * + * @param {Either} to - The target account to approve + * @param {Uint<128>} tokenId - The token to approve + * @param {Either} auth - An account authorized to operate on all tokens held by the owner the token + * @return {[]} - None. + */ + export circuit _approve( + to: Either, + tokenId: Uint<128>, + auth: Either + ): [] { + Initializable_assertInitialized(); + if (!Utils_isKeyOrAddressZero(auth)) { + const owner = _requireOwned(tokenId); + + // We do not use _isAuthorized because single-token approvals should not be able to call approve + assert (owner == auth || isApprovedForAll(owner, auth)) "NonFungibleToken: Invalid Approver"; + } + + _tokenApprovals.insert(tokenId, to); + } + + /** + * @description Approve `operator` to operate on all of `owner` tokens + * + * Requirements: + * - `operator` can't be the address zero. + * + * @param {Either} owner - Owner of a token + * @param {Either} operator - The account to approve + * @param {Boolean} approved - A boolean determining if `operator` may operate on all of `owner` tokens + * @return {[]} - None. + */ + export circuit _setApprovalForAll( + owner: Either, + operator: Either, + approved: Boolean + ): [] { + Initializable_assertInitialized(); + assert !Utils_isKeyOrAddressZero(operator) "NonFungibleToken: Invalid Operator"; + + if (!_operatorApprovals.member(owner)) { + _operatorApprovals.insert( + owner, + default, Boolean>> + ); + } + + _operatorApprovals.lookup(owner).insert(operator, approved); + } + + /** + * @description Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). + * Returns the owner. + * + * @param {Uint<128>} tokenId - The token that should be owned + * @return {Either} - The owner of `tokenId` + */ + export circuit _requireOwned(tokenId: Uint<128>): Either { + Initializable_assertInitialized(); + const owner = _ownerOf(tokenId); + + assert !Utils_isKeyOrAddressZero(owner) "NonFungibleToken: Nonexistent Token"; + return owner; + } +} + From a4a9b456a97ffa9fa7d1d0680746fc5bf8422420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 14:53:24 -0400 Subject: [PATCH 186/282] Fmt Missing Features --- .../nonFungibleToken/src/nonFungibleToken.compact | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/contracts/nonFungibleToken/src/nonFungibleToken.compact b/contracts/nonFungibleToken/src/nonFungibleToken.compact index 7a78621d..bbdd4930 100644 --- a/contracts/nonFungibleToken/src/nonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/nonFungibleToken.compact @@ -29,12 +29,13 @@ pragma language_version >= 0.15.0; * - Drop _unsafeTransfer and remove `isContract` guard from `transfer`. * - By this point, anyone using _unsafeTransfer should have migrated to the now C2C-capable `transfer`. * - * @notice TODO List - Missing Features and Improvements: - * @notice TODO: Support Uint256 token IDs - * @notice TODO: Implement Transfer/Approval events - * @notice TODO: Add safe transfer functions - * @notice TODO: Add _baseURI() support - * @notice TODO: Add ERC165 support + * @notice Missing Features and Improvements: + * + * - Uint256 token IDs + * - Transfer/Approval events + * - safeTransfer functions + * - _baseURI() support + * - An ERC165-like interface */ module NonFungibleToken { From e4476720c905306e12c3cae5275600e665002487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 15:06:20 -0400 Subject: [PATCH 187/282] Git naming fix --- .../src/{nonFungibleToken.compact => NonFungibleToken.compact} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename contracts/nonFungibleToken/src/{nonFungibleToken.compact => NonFungibleToken.compact} (100%) diff --git a/contracts/nonFungibleToken/src/nonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact similarity index 100% rename from contracts/nonFungibleToken/src/nonFungibleToken.compact rename to contracts/nonFungibleToken/src/NonFungibleToken.compact From 61a351e6b8598dc32057299eb0cc9bb116e390b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 16:00:28 -0400 Subject: [PATCH 188/282] Update method documentation with Requirements sections --- .../src/NonFungibleToken.compact | 109 +++++++++++++----- 1 file changed, 80 insertions(+), 29 deletions(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index bbdd4930..453d4d4b 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -55,6 +55,9 @@ module NonFungibleToken { /** * @description Initializes the contract by setting the name and symbol. * + * Requirements: + * - The contract must not have been initialized. + * * @param {Opaque<"string">} name_ - The name of the token. * @param {Opaque<"string">} symbol_ - The symbol of the token. * @return {[]} - None. @@ -63,6 +66,7 @@ module NonFungibleToken { name_: Opaque<"string">, symbol_: Opaque<"string"> ): [] { + Initializable_assertNotInitialized(); Initializable_initialize(); _name = name_; _symbol = symbol_; @@ -71,6 +75,9 @@ module NonFungibleToken { /** * @description Returns the number of tokens in `owner`'s account. * + * Requirements: + * - The contract must have been initialized. + * * @param {Either)} owner - The account to query. * @return {Uint<128>} - The number of tokens in `owner`'s account. */ @@ -86,6 +93,10 @@ module NonFungibleToken { /** * @description Returns the owner of the `tokenId` token. * + * Requirements: + * - The contract must have been initialized. + * - The `tokenId` must exist. + * * @param {Uint<128>} tokenId - The identifier for a token. * @return {Either} - The account that owns the token. */ @@ -97,6 +108,9 @@ module NonFungibleToken { /** * @description Returns the token name. * + * Requirements: + * - The contract must have been initialized. + * * @return {Opaque<"string">} - The token name. */ export circuit name(): Opaque<"string"> { @@ -107,6 +121,9 @@ module NonFungibleToken { /** * @description Returns the symbol of the token. * + * Requirements: + * - The contract must have been initialized. + * * @return {Opaque<"string">} - The token symbol. */ export circuit symbol(): Opaque<"string"> { @@ -117,6 +134,10 @@ module NonFungibleToken { /** * @description Returns the token URI for the given `tokenId`. * + * Requirements: + * - The contract must have been initialized. + * - The `tokenId` must exist. + * * @notice Midnight does not support native strings and string operations * within the Compact language, e.g. concatenating a base URI + token ID are not possible * like in other NFT implementations. Therefore, we propose the URI storage @@ -135,7 +156,10 @@ module NonFungibleToken { /** * @description Sets the the URI as `tokenURI` for the given `tokenId`. - * The `tokenId` must exist. + * + * Requirements: + * - The contract must have been initialized. + * - The `tokenId` must exist. * * @notice The URI for a given NFT is usually set when the NFT is minted. * @@ -157,7 +181,7 @@ module NonFungibleToken { * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: - * + * - The contract must have been initialized. * - The caller must either own the token or be an approved operator. * - `tokenId` must exist. * @@ -180,6 +204,11 @@ module NonFungibleToken { /** * @description Returns the account approved for `tokenId` token. + * + * Requirements: + * - The contract must have been initialized. + * - `tokenId` must exist. + * * @param {Uint<128>} tokenId - The token an account may be approved to manage * @return {Either} Operator- The account approved to manage the token */ @@ -195,7 +224,7 @@ module NonFungibleToken { * Operators can call {transferFrom} for any token owned by the caller. * * Requirements: - * + * - The contract must have been initialized. * - The `operator` cannot be the address zero. * * @param {Either} operator - An operator to manage the caller's tokens @@ -218,6 +247,9 @@ module NonFungibleToken { /** * @description Returns if the `operator` is allowed to manage all of the assets of `owner`. * + * Requirements: + * - The contract must have been initialized. + * * @param {Either} owner - The owner of a token * @param {Either} operator - An account that may operate on `owner`'s tokens * @return {Boolean} - A boolean determining if `operator` is allowed to manage all of the tokens of `owner` @@ -238,7 +270,7 @@ module NonFungibleToken { * @description Transfers `tokenId` token from `from` to `to`. * * Requirements: - * + * - The contract must have been initialized. * - `from` cannot be the zero address. * - `to` cannot be the zero address or a ContractAddress. * - `tokenId` token must be owned by `from`. @@ -271,17 +303,17 @@ module NonFungibleToken { /** * @description Transfers `tokenId` token from `from` to `to`. It does NOT check if the recipient is a ContractAddress. * - * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts - * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the - * ContractAddress - * * Requirements: - * + * - The contract must have been initialized. * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the + * ContractAddress + * * @param {Either} from - The source account from which the token is being transfered * @param {Either} to - The target account to transfer token to * @param {Uint<128>} tokenId - The token being transfered @@ -308,6 +340,9 @@ module NonFungibleToken { /** * @description Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist * + * Requirements: + * - The contract must have been initialized. + * * @param {Uint<128>} tokenId - The target token of the owner query * @return {Either} - The owner of the token */ @@ -321,7 +356,10 @@ module NonFungibleToken { } /** - * @description Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. + * @description Returns the approved address for `tokenId`. Returns the zero address if `tokenId` is not minted. + * + * Requirements: + * - The contract must have been initialized. * * @param {Uint<128>} tokenId - The token to query * @return {Either} - An account approved to spend `tokenId` @@ -338,6 +376,9 @@ module NonFungibleToken { * @description Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in * particular (ignoring whether it is owned by `owner`). * + * Requirements: + * - The contract must have been initialized. + * * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this * assumption. * @@ -360,9 +401,10 @@ module NonFungibleToken { /** * @description Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. - * Reverts if: - * - `spender` does not have approval from `owner` for `tokenId`. - * - `spender` does not have approval to manage all of `owner`'s assets. + * + * Requirements: + * - The contract must have been initialized. + * - `spender` has approval from `owner` for `tokenId` OR `spender` has approval to manage all of `owner`'s assets. * * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this * assumption. @@ -388,8 +430,10 @@ module NonFungibleToken { * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. * - * The `auth` argument is optional. If the value passed is non 0, then this function will check that - * `auth` is either the owner of the token, or approved to operate on the token (by the owner). + * Requirements: + * - The contract must have been initialized. + * - If `auth` is non 0, then this function will check that `auth` is either the owner of the token, + * or approved to operate on the token (by the owner). * * @param {Either} to - The intended recipient of the token transfer * @param {Uint<128>} tokenId - The token being transfered @@ -434,7 +478,7 @@ module NonFungibleToken { * @description Mints `tokenId` and transfers it to `to`. * * Requirements: - * + * - The contract must have been initialized. * - `tokenId` must not exist. * - `to` cannot be the zero address or a ContractAddress. * @@ -458,14 +502,14 @@ module NonFungibleToken { /** * @description Mints `tokenId` and transfers it to `to`. It does NOT check if the recipient is a ContractAddress. * - * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts - * may result in a permanent loss of the token. - * * Requirements: - * + * - The contract must have been initialized. * - `tokenId` must not exist. * - `to` cannot be the zero address. * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. + * * @param {Either} to - The account receiving `tokenId` * @param {Uint<128>} tokenId - The token to transfer * @return {[]} - None. @@ -488,7 +532,7 @@ module NonFungibleToken { * This circuit does not check if the sender is authorized to operate on the token. * * Requirements: - * + * - The contract must have been initialized. * - `tokenId` must exist. * * @param {Uint<128>} tokenId - The token to burn @@ -505,7 +549,7 @@ module NonFungibleToken { * As opposed to {transferFrom}, this imposes no restrictions on own_public_key(). * * Requirements: - * + * - The contract must have been initialized. * - `to` cannot be the zero address or a ContractAddress. * - `tokenId` token must be owned by `from`. * @@ -534,15 +578,15 @@ module NonFungibleToken { * As opposed to {_unsafeTransferFrom}, this imposes no restrictions on own_public_key(). * It does NOT check if the recipient is a ContractAddress. * - * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts - * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the - * ContractAddress - * * Requirements: - * + * - The contract must have been initialized. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the + * ContractAddress + * * @param {Either} from - The source account of the token transfer * @param {Either} to - The target account of the token transfer * @param {Uint<128>} tokenId - The token to transfer @@ -565,8 +609,10 @@ module NonFungibleToken { /** * @description Approve `to` to operate on `tokenId` * - * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is - * either the owner of the token, or approved to operate on all tokens held by this owner. + * Requirements: + * - The contract must have been initialized. + * - If `auth` is non 0, then this function will check that `auth` is either the owner of the token, + * or approved to operate on the token (by the owner). * * @param {Either} to - The target account to approve * @param {Uint<128>} tokenId - The token to approve @@ -593,6 +639,7 @@ module NonFungibleToken { * @description Approve `operator` to operate on all of `owner` tokens * * Requirements: + * - The contract must have been initialized. * - `operator` can't be the address zero. * * @param {Either} owner - Owner of a token @@ -622,6 +669,10 @@ module NonFungibleToken { * @description Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). * Returns the owner. * + * Requirements: + * - The contract must have been initialized. + * - `tokenId` must exist. + * * @param {Uint<128>} tokenId - The token that should be owned * @return {Either} - The owner of `tokenId` */ From 27eefc222d165c5e18cc60355c6db87978cc0bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 16:02:38 -0400 Subject: [PATCH 189/282] Split requirement --- contracts/nonFungibleToken/src/NonFungibleToken.compact | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index 453d4d4b..a73156c2 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -272,7 +272,8 @@ module NonFungibleToken { * Requirements: * - The contract must have been initialized. * - `from` cannot be the zero address. - * - `to` cannot be the zero address or a ContractAddress. + * - `to` cannot be the zero address. + * - `to` cannot be ContractAddress. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * @@ -480,7 +481,8 @@ module NonFungibleToken { * Requirements: * - The contract must have been initialized. * - `tokenId` must not exist. - * - `to` cannot be the zero address or a ContractAddress. + * - `to` cannot be the zero address. + * - `to` cannot be ContractAddress. * * @param {Either} to - The account receiving `tokenId` * @param {Uint<128>} tokenId - The token to transfer @@ -550,7 +552,8 @@ module NonFungibleToken { * * Requirements: * - The contract must have been initialized. - * - `to` cannot be the zero address or a ContractAddress. + * - `to` cannot be the zero address. + * - `to` cannot be ContractAddress. * - `tokenId` token must be owned by `from`. * * @param {Either} from - The source account of the token transfer From 2cd1ab487cac664d566865f5af38d938f9972f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 16:09:24 -0400 Subject: [PATCH 190/282] Remove duplicate code --- .../src/NonFungibleToken.compact | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index a73156c2..45518182 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -289,16 +289,8 @@ module NonFungibleToken { ): [] { Initializable_assertInitialized(); assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; - assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; - // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists - // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. - const auth = left(own_public_key()); - const previousOwner = _update( - to, - tokenId, - auth - ); - assert previousOwner == from "NonFungibleToken: Incorrect Owner"; + + _unsafeTransferFrom(from, to, tokenId); } /** @@ -494,11 +486,8 @@ module NonFungibleToken { ): [] { Initializable_assertInitialized(); assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; - assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; - const previousOwner = _update(to, tokenId, burn_address()); - - assert Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Invalid Sender"; + _unsafeMint(to, tokenId); } /** @@ -568,12 +557,8 @@ module NonFungibleToken { ): [] { Initializable_assertInitialized(); assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; - assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; - - const previousOwner = _update(to, tokenId, burn_address()); - assert !Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Nonexistent Token"; - assert previousOwner == from "NonFungibleToken: Incorrect Owner"; + _unsafeTransfer(from, to); } /** From c012cb0835932a8595e27660ccd01d8a5afbafe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 16:18:40 -0400 Subject: [PATCH 191/282] Remove export from _update, reorg code --- .../src/NonFungibleToken.compact | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index 45518182..02c4913a 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -419,54 +419,6 @@ module NonFungibleToken { } } - /** - * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner - * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. - * - * Requirements: - * - The contract must have been initialized. - * - If `auth` is non 0, then this function will check that `auth` is either the owner of the token, - * or approved to operate on the token (by the owner). - * - * @param {Either} to - The intended recipient of the token transfer - * @param {Uint<128>} tokenId - The token being transfered - * @param {Either} auth - An account authorized to transfer the token - * @return {Either} - Owner of the token before it was transfered - */ - export circuit _update( - to: Either, - tokenId: Uint<128>, - auth: Either - ): Either { - Initializable_assertInitialized(); - const from = _ownerOf(tokenId); - - // Perform (optional) operator check - if (!Utils_isKeyOrAddressZero(auth)) { - _checkAuthorized(from, auth, tokenId); - } - - // Execute the update - if (!Utils_isKeyOrAddressZero(from)) { - // Clear approval. No need to re-authorize - _approve(burn_address(), tokenId, burn_address()); - const newBalance = _balances.lookup(from) - 1 as Uint<128>; - _balances.insert(from, newBalance); - } - - if (!Utils_isKeyOrAddressZero(to)) { - if (!_balances.member(to)) { - _balances.insert(to, 0); - } - const newBalance = _balances.lookup(to) + 1 as Uint<128>; - _balances.insert(to, newBalance); - } - - _owners.insert(tokenId, to); - - return from; - } - /** * @description Mints `tokenId` and transfers it to `to`. * @@ -671,5 +623,53 @@ module NonFungibleToken { assert !Utils_isKeyOrAddressZero(owner) "NonFungibleToken: Nonexistent Token"; return owner; } + + /** + * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner + * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. + * + * Requirements: + * - The contract must have been initialized. + * - If `auth` is non 0, then this function will check that `auth` is either the owner of the token, + * or approved to operate on the token (by the owner). + * + * @param {Either} to - The intended recipient of the token transfer + * @param {Uint<128>} tokenId - The token being transfered + * @param {Either} auth - An account authorized to transfer the token + * @return {Either} - Owner of the token before it was transfered + */ + circuit _update( + to: Either, + tokenId: Uint<128>, + auth: Either + ): Either { + Initializable_assertInitialized(); + const from = _ownerOf(tokenId); + + // Perform (optional) operator check + if (!Utils_isKeyOrAddressZero(auth)) { + _checkAuthorized(from, auth, tokenId); + } + + // Execute the update + if (!Utils_isKeyOrAddressZero(from)) { + // Clear approval. No need to re-authorize + _approve(burn_address(), tokenId, burn_address()); + const newBalance = _balances.lookup(from) - 1 as Uint<128>; + _balances.insert(from, newBalance); + } + + if (!Utils_isKeyOrAddressZero(to)) { + if (!_balances.member(to)) { + _balances.insert(to, 0); + } + const newBalance = _balances.lookup(to) + 1 as Uint<128>; + _balances.insert(to, newBalance); + } + + _owners.insert(tokenId, to); + + return from; + } } From cd09a9195be2165dca6b6fd31e5b5f8e8a768092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 16:37:42 -0400 Subject: [PATCH 192/282] Fix compiler error --- contracts/nonFungibleToken/src/NonFungibleToken.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index 02c4913a..87d9ea41 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -510,7 +510,7 @@ module NonFungibleToken { Initializable_assertInitialized(); assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; - _unsafeTransfer(from, to); + _unsafeTransfer(from, to, tokenId); } /** From 1587541488363721135a13ea4d3d1b4b7c7fce1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 16:38:11 -0400 Subject: [PATCH 193/282] Add NonFungibleTesting file --- .../test/mocks/MockNonFungibleToken.compact | 2 +- .../MockUninitializedNonFungibleToken.compact | 158 ++++ .../mocks/NonFungibleTokenTesting.compact | 674 ++++++++++++++++++ 3 files changed, 833 insertions(+), 1 deletion(-) create mode 100644 contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact create mode 100644 contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact diff --git a/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact index e49f236a..ff75aa7d 100644 --- a/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact @@ -2,7 +2,7 @@ pragma language_version >= 0.15.0; import CompactStandardLibrary; -import "../../NonFungibleToken" prefix NonFungibleToken_; +import "NonFungibleTokenTesting" prefix NonFungibleToken_; export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; diff --git a/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact b/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact new file mode 100644 index 00000000..ca24d4e7 --- /dev/null +++ b/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact @@ -0,0 +1,158 @@ +pragma language_version >= 0.15.0; + +import CompactStandardLibrary; + +import "NonFungibleTokenTesting" prefix NonFungibleToken_; + +export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; + +export circuit name(): Opaque<"string"> { + return NonFungibleToken_name(); +} + +export circuit symbol(): Opaque<"string"> { + return NonFungibleToken_symbol(); +} + +export circuit balanceOf(account: Either): Uint<128> { + return NonFungibleToken_balanceOf(account); +} + +export circuit ownerOf(tokenId: Uint<128>): Either { + return NonFungibleToken_ownerOf(tokenId); +} + +export circuit tokenURI(tokenId: Uint<128>): Opaque<"string"> { + return NonFungibleToken_tokenURI(tokenId); +} + +export circuit approve( + to: Either, + tokenId: Uint<128> +): [] { + return NonFungibleToken_approve(to, tokenId); +} + +export circuit getApproved(tokenId: Uint<128>): Either { + return NonFungibleToken_getApproved(tokenId); +} + +export circuit setApprovalForAll( + operator: Either, + approved: Boolean +): [] { + return NonFungibleToken_setApprovalForAll(operator, approved); +} + +export circuit isApprovedForAll( + owner: Either, + operator: Either +): Boolean { + return NonFungibleToken_isApprovedForAll(owner, operator); +} + +export circuit transferFrom( + from: Either, + to: Either, + tokenId: Uint<128> +): [] { + return NonFungibleToken_transferFrom(from, to, tokenId); +} + +export circuit _requireOwned(tokenId: Uint<128>): Either { + return NonFungibleToken__requireOwned(tokenId); +} + +export circuit _ownerOf(tokenId: Uint<128>): Either { + return NonFungibleToken__ownerOf(tokenId); +} + +export circuit _update( + to: Either, + tokenId: Uint<128>, + auth: Either +): Either { + return NonFungibleToken__update(to, tokenId, auth); +} + +export circuit _approve( + to: Either, + tokenId: Uint<128>, + auth: Either +): [] { + return NonFungibleToken__approve(to, tokenId, auth); +} + +export circuit _checkAuthorized( + owner: Either, + spender: Either, + tokenId: Uint<128> +): [] { + return NonFungibleToken__checkAuthorized(owner, spender, tokenId); +} + +export circuit _isAuthorized( + owner: Either, + spender: Either, + tokenId: Uint<128> +): Boolean { + return NonFungibleToken__isAuthorized(owner, spender, tokenId); +} + +export circuit _getApproved(tokenId: Uint<128>): Either { + return NonFungibleToken__getApproved(tokenId); +} + +export circuit _setApprovalForAll( + owner: Either, + operator: Either, + approved: Boolean +): [] { + return NonFungibleToken__setApprovalForAll(owner, operator, approved); +} + +export circuit _mint( + to: Either, + tokenId: Uint<128> +): [] { + return NonFungibleToken__mint(to, tokenId); +} + +export circuit _burn(tokenId: Uint<128>): [] { + return NonFungibleToken__burn(tokenId); +} + +export circuit _transfer( + from: Either, + to: Either, + tokenId: Uint<128> +): [] { + return NonFungibleToken__transfer(from, to, tokenId); +} + +export circuit _setTokenURI(tokenId: Uint<128>, tokenURI: Opaque<"string">): [] { + return NonFungibleToken__setTokenURI(tokenId, tokenURI); +} + +export circuit _unsafeTransferFrom( + from: Either, + to: Either, + tokenId: Uint<128> +): [] { + return NonFungibleToken__unsafeTransferFrom(from, to, tokenId); +} + +export circuit _unsafeTransfer( + from: Either, + to: Either, + tokenId: Uint<128> +): [] { + return NonFungibleToken__unsafeTransfer(from, to, tokenId); +} + +export circuit _unsafeMint( + to: Either, + tokenId: Uint<128> +): [] { + return NonFungibleToken__unsafeMint(to, tokenId); +} diff --git a/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact b/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact new file mode 100644 index 00000000..fa53308d --- /dev/null +++ b/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact @@ -0,0 +1,674 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.15.0; + +/** + * @module NonFungibleToken + * @description An unshielded Non-Fungible Token library. + * + * @notice One notable difference regarding this implementation and the EIP20 spec + * consists of the token size. Uint<128> is used as the token size because Uint<256> + * cannot be supported. + * This is due to encoding limits on the midnight circuit backend: + * https://github.com/midnightntwrk/compactc/issues/929 + * + * @notice At the moment Midnight does not support contract-to-contract communication, but + * there are ongoing efforts to enable this in the future. Thus, the main circuits of this module + * restrict developers from sending tokens to contracts; however, we provide developers + * the ability to experiment with sending tokens to contracts using the `_unsafe` + * transfer methods. Once contract-to-contract communication is available we will follow the + * deprecation plan outlined below: + * + * Initial Minor Version Change: + * + * - Mark _unsafeTransfer as deprecated and emit a warning if possible. + * - Keep its implementation intact so existing callers continue to work. + * + * Later Major Version Change: + * + * - Drop _unsafeTransfer and remove `isContract` guard from `transfer`. + * - By this point, anyone using _unsafeTransfer should have migrated to the now C2C-capable `transfer`. + * + * @notice Missing Features and Improvements: + * + * - Uint256 token IDs + * - Transfer/Approval events + * - safeTransfer functions + * - _baseURI() support + * - An ERC165-like interface + */ + +module NonFungibleTokenTesting { + import CompactStandardLibrary; + import "../../node_modules/@openzeppelin-midnight/utils/src/Utils" prefix Utils_; + import "../../node_modules/@openzeppelin-midnight/utils/src/Initializable" prefix Initializable_; + + /// Public state + export sealed ledger _name: Opaque<"string">; + export sealed ledger _symbol: Opaque<"string">; + export ledger _owners: Map, Either>; + export ledger _balances: Map, Uint<128>>; + export ledger _tokenApprovals: Map, Either>; + export ledger _operatorApprovals: Map, Map, Boolean>>; + export ledger _tokenURIs: Map, Opaque<"string">>; + + /** + * @description Initializes the contract by setting the name and symbol. + * + * Requirements: + * - The contract must not have been initialized. + * + * @param {Opaque<"string">} name_ - The name of the token. + * @param {Opaque<"string">} symbol_ - The symbol of the token. + * @return {[]} - None. + */ + export circuit initialize( + name_: Opaque<"string">, + symbol_: Opaque<"string"> + ): [] { + Initializable_assertNotInitialized(); + Initializable_initialize(); + _name = name_; + _symbol = symbol_; + } + + /** + * @description Returns the number of tokens in `owner`'s account. + * + * Requirements: + * - The contract must have been initialized. + * + * @param {Either)} owner - The account to query. + * @return {Uint<128>} - The number of tokens in `owner`'s account. + */ + export circuit balanceOf(owner: Either): Uint<128> { + Initializable_assertInitialized(); + if (!_balances.member(owner)) { + return 0; + } + + return _balances.lookup(owner); + } + + /** + * @description Returns the owner of the `tokenId` token. + * + * Requirements: + * - The contract must have been initialized. + * - The `tokenId` must exist. + * + * @param {Uint<128>} tokenId - The identifier for a token. + * @return {Either} - The account that owns the token. + */ + export circuit ownerOf(tokenId: Uint<128>): Either { + Initializable_assertInitialized(); + return _requireOwned(tokenId); + } + + /** + * @description Returns the token name. + * + * Requirements: + * - The contract must have been initialized. + * + * @return {Opaque<"string">} - The token name. + */ + export circuit name(): Opaque<"string"> { + Initializable_assertInitialized(); + return _name; + } + + /** + * @description Returns the symbol of the token. + * + * Requirements: + * - The contract must have been initialized. + * + * @return {Opaque<"string">} - The token symbol. + */ + export circuit symbol(): Opaque<"string"> { + Initializable_assertInitialized(); + return _symbol; + } + + /** + * @description Returns the token URI for the given `tokenId`. + * + * Requirements: + * - The contract must have been initialized. + * - The `tokenId` must exist. + * + * @notice Midnight does not support native strings and string operations + * within the Compact language, e.g. concatenating a base URI + token ID are not possible + * like in other NFT implementations. Therefore, we propose the URI storage + * approach; whereby, NFTs may or may not have unique "base" URIs. + * It's up to the implementation to decide on how to handle this. + * + * @param {Uint<128>} tokenId - The identifier for a token. + * @returns {Opaque<"string">} - the token id's URI. + */ + export circuit tokenURI(tokenId: Uint<128>): Opaque<"string"> { + Initializable_assertInitialized(); + _requireOwned(tokenId); + + return _tokenURIs.lookup(tokenId); + } + + /** + * @description Sets the the URI as `tokenURI` for the given `tokenId`. + * + * Requirements: + * - The contract must have been initialized. + * - The `tokenId` must exist. + * + * @notice The URI for a given NFT is usually set when the NFT is minted. + * + * @param {Uint<128>} tokenId - The identifier of the token. + * @param {Opaque<"string">} tokenURI - The URI of `tokenId`. + * @return {[]} - None. + */ + export circuit _setTokenURI(tokenId: Uint<128>, tokenURI: Opaque<"string">): [] { + Initializable_assertInitialized(); + _requireOwned(tokenId); + + return _tokenURIs.insert(tokenId, tokenURI); + } + + /** + * @description Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * - The contract must have been initialized. + * - The caller must either own the token or be an approved operator. + * - `tokenId` must exist. + * + * @param {Either} to - The account receiving the approval + * @param {Uint<128>} tokenId - The token `to` may be permitted to transfer + * @return {[]} - None. + */ + export circuit approve( + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + const auth = left(own_public_key()); + _approve( + to, + tokenId, + auth + ); + } + + /** + * @description Returns the account approved for `tokenId` token. + * + * Requirements: + * - The contract must have been initialized. + * - `tokenId` must exist. + * + * @param {Uint<128>} tokenId - The token an account may be approved to manage + * @return {Either} Operator- The account approved to manage the token + */ + export circuit getApproved(tokenId: Uint<128>): Either { + Initializable_assertInitialized(); + _requireOwned(tokenId); + + return _getApproved(tokenId); + } + + /** + * @description Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} for any token owned by the caller. + * + * Requirements: + * - The contract must have been initialized. + * - The `operator` cannot be the address zero. + * + * @param {Either} operator - An operator to manage the caller's tokens + * @param {Boolean} approved - A boolean determining if `operator` may manage all tokens of the caller + * @return {[]} - None. + */ + export circuit setApprovalForAll( + operator: Either, + approved: Boolean + ): [] { + Initializable_assertInitialized(); + const owner = left(own_public_key()); + _setApprovalForAll( + owner, + operator, + approved + ); + } + + /** + * @description Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * Requirements: + * - The contract must have been initialized. + * + * @param {Either} owner - The owner of a token + * @param {Either} operator - An account that may operate on `owner`'s tokens + * @return {Boolean} - A boolean determining if `operator` is allowed to manage all of the tokens of `owner` + */ + export circuit isApprovedForAll( + owner: Either, + operator: Either + ): Boolean { + Initializable_assertInitialized(); + if (_operatorApprovals.member(owner) && _operatorApprovals.lookup(owner).member(operator)) { + return _operatorApprovals.lookup(owner).lookup(operator); + } else { + return false; + } + } + + /** + * @description Transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * - The contract must have been initialized. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `to` cannot be ContractAddress. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * @param {Either} from - The source account from which the token is being transfered + * @param {Either} to - The target account to transfer token to + * @param {Uint<128>} tokenId - The token being transfered + * @return {[]} - None. + */ + export circuit transferFrom( + from: Either, + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; + + _unsafeTransferFrom(from, to, tokenId); + } + + /** + * @description Transfers `tokenId` token from `from` to `to`. It does NOT check if the recipient is a ContractAddress. + * + * Requirements: + * - The contract must have been initialized. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the + * ContractAddress + * + * @param {Either} from - The source account from which the token is being transfered + * @param {Either} to - The target account to transfer token to + * @param {Uint<128>} tokenId - The token being transfered + * @return {[]} - None. + */ + export circuit _unsafeTransferFrom( + from: Either, + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; + // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists + // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. + const auth = left(own_public_key()); + const previousOwner = _update( + to, + tokenId, + auth + ); + assert previousOwner == from "NonFungibleToken: Incorrect Owner"; + } + + /** + * @description Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist + * + * Requirements: + * - The contract must have been initialized. + * + * @param {Uint<128>} tokenId - The target token of the owner query + * @return {Either} - The owner of the token + */ + export circuit _ownerOf(tokenId: Uint<128>): Either { + Initializable_assertInitialized(); + if (!_owners.member(tokenId)) { + return burn_address(); + } + + return _owners.lookup(tokenId); + } + + /** + * @description Returns the approved address for `tokenId`. Returns the zero address if `tokenId` is not minted. + * + * Requirements: + * - The contract must have been initialized. + * + * @param {Uint<128>} tokenId - The token to query + * @return {Either} - An account approved to spend `tokenId` + */ + export circuit _getApproved(tokenId: Uint<128>): Either { + Initializable_assertInitialized(); + if (!_tokenApprovals.member(tokenId)) { + return burn_address(); + } + return _tokenApprovals.lookup(tokenId); + } + + /** + * @description Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in + * particular (ignoring whether it is owned by `owner`). + * + * Requirements: + * - The contract must have been initialized. + * + * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this + * assumption. + * + * @param {Either} owner - Owner of the token + * @param {Either} spender - Account that wishes to spend `tokenId` + * @param {Uint<128>} tokenId - Token to spend + * @return {Boolean} - A boolean determining if `spender` may manage `tokenId` + */ + export circuit _isAuthorized( + owner: Either, + spender: Either, + tokenId: Uint<128> + ): Boolean { + Initializable_assertInitialized(); + return ( + !Utils_isKeyOrAddressZero(spender) && + (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender) + ); + } + + /** + * @description Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. + * + * Requirements: + * - The contract must have been initialized. + * - `spender` has approval from `owner` for `tokenId` OR `spender` has approval to manage all of `owner`'s assets. + * + * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this + * assumption. + * + * @param {Either} owner - Owner of the token + * @param {Either} spender - Account operating on `tokenId` + * @param {Uint<128>} tokenId - The token to spend + * @return {[]} - None. + */ + export circuit _checkAuthorized( + owner: Either, + spender: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + if (!_isAuthorized(owner, spender, tokenId)) { + assert !Utils_isKeyOrAddressZero(owner) "NonFungibleToken: Nonexistent Token"; + assert false "NonFungibleToken: Insufficient Approval"; + } + } + + /** + * @description Mints `tokenId` and transfers it to `to`. + * + * Requirements: + * - The contract must have been initialized. + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * - `to` cannot be ContractAddress. + * + * @param {Either} to - The account receiving `tokenId` + * @param {Uint<128>} tokenId - The token to transfer + * @return {[]} - None. + */ + export circuit _mint( + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; + + _unsafeMint(to, tokenId); + } + + /** + * @description Mints `tokenId` and transfers it to `to`. It does NOT check if the recipient is a ContractAddress. + * + * Requirements: + * - The contract must have been initialized. + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. + * + * @param {Either} to - The account receiving `tokenId` + * @param {Uint<128>} tokenId - The token to transfer + * @return {[]} - None. + */ + export circuit _unsafeMint( + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; + + const previousOwner = _update(to, tokenId, burn_address()); + + assert Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Invalid Sender"; + } + + /** + * @description Destroys `tokenId`. + * The approval is cleared when the token is burned. + * This circuit does not check if the sender is authorized to operate on the token. + * + * Requirements: + * - The contract must have been initialized. + * - `tokenId` must exist. + * + * @param {Uint<128>} tokenId - The token to burn + * @return {[]} - None. + */ + export circuit _burn(tokenId: Uint<128>): [] { + Initializable_assertInitialized(); + const previousOwner = _update(burn_address(), tokenId, burn_address()); + assert !Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Invalid Sender"; + } + + /** + * @description Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on own_public_key(). + * + * Requirements: + * - The contract must have been initialized. + * - `to` cannot be the zero address. + * - `to` cannot be ContractAddress. + * - `tokenId` token must be owned by `from`. + * + * @param {Either} from - The source account of the token transfer + * @param {Either} to - The target account of the token transfer + * @param {Uint<128>} tokenId - The token to transfer + * @return {[]} - None. + */ + export circuit _transfer( + from: Either, + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; + + _unsafeTransfer(from, to, tokenId); + } + + /** + * @description Transfers `tokenId` from `from` to `to`. + * As opposed to {_unsafeTransferFrom}, this imposes no restrictions on own_public_key(). + * It does NOT check if the recipient is a ContractAddress. + * + * Requirements: + * - The contract must have been initialized. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the + * ContractAddress + * + * @param {Either} from - The source account of the token transfer + * @param {Either} to - The target account of the token transfer + * @param {Uint<128>} tokenId - The token to transfer + * @return {[]} - None. + */ + export circuit _unsafeTransfer( + from: Either, + to: Either, + tokenId: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; + + const previousOwner = _update(to, tokenId, burn_address()); + + assert !Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Nonexistent Token"; + assert previousOwner == from "NonFungibleToken: Incorrect Owner"; + } + + /** + * @description Approve `to` to operate on `tokenId` + * + * Requirements: + * - The contract must have been initialized. + * - If `auth` is non 0, then this function will check that `auth` is either the owner of the token, + * or approved to operate on the token (by the owner). + * + * @param {Either} to - The target account to approve + * @param {Uint<128>} tokenId - The token to approve + * @param {Either} auth - An account authorized to operate on all tokens held by the owner the token + * @return {[]} - None. + */ + export circuit _approve( + to: Either, + tokenId: Uint<128>, + auth: Either + ): [] { + Initializable_assertInitialized(); + if (!Utils_isKeyOrAddressZero(auth)) { + const owner = _requireOwned(tokenId); + + // We do not use _isAuthorized because single-token approvals should not be able to call approve + assert (owner == auth || isApprovedForAll(owner, auth)) "NonFungibleToken: Invalid Approver"; + } + + _tokenApprovals.insert(tokenId, to); + } + + /** + * @description Approve `operator` to operate on all of `owner` tokens + * + * Requirements: + * - The contract must have been initialized. + * - `operator` can't be the address zero. + * + * @param {Either} owner - Owner of a token + * @param {Either} operator - The account to approve + * @param {Boolean} approved - A boolean determining if `operator` may operate on all of `owner` tokens + * @return {[]} - None. + */ + export circuit _setApprovalForAll( + owner: Either, + operator: Either, + approved: Boolean + ): [] { + Initializable_assertInitialized(); + assert !Utils_isKeyOrAddressZero(operator) "NonFungibleToken: Invalid Operator"; + + if (!_operatorApprovals.member(owner)) { + _operatorApprovals.insert( + owner, + default, Boolean>> + ); + } + + _operatorApprovals.lookup(owner).insert(operator, approved); + } + + /** + * @description Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). + * Returns the owner. + * + * Requirements: + * - The contract must have been initialized. + * - `tokenId` must exist. + * + * @param {Uint<128>} tokenId - The token that should be owned + * @return {Either} - The owner of `tokenId` + */ + export circuit _requireOwned(tokenId: Uint<128>): Either { + Initializable_assertInitialized(); + const owner = _ownerOf(tokenId); + + assert !Utils_isKeyOrAddressZero(owner) "NonFungibleToken: Nonexistent Token"; + return owner; + } + + /** + * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner + * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. + * + * Requirements: + * - The contract must have been initialized. + * - If `auth` is non 0, then this function will check that `auth` is either the owner of the token, + * or approved to operate on the token (by the owner). + * + * @param {Either} to - The intended recipient of the token transfer + * @param {Uint<128>} tokenId - The token being transfered + * @param {Either} auth - An account authorized to transfer the token + * @return {Either} - Owner of the token before it was transfered + */ + export circuit _update( + to: Either, + tokenId: Uint<128>, + auth: Either + ): Either { + Initializable_assertInitialized(); + const from = _ownerOf(tokenId); + + // Perform (optional) operator check + if (!Utils_isKeyOrAddressZero(auth)) { + _checkAuthorized(from, auth, tokenId); + } + + // Execute the update + if (!Utils_isKeyOrAddressZero(from)) { + // Clear approval. No need to re-authorize + _approve(burn_address(), tokenId, burn_address()); + const newBalance = _balances.lookup(from) - 1 as Uint<128>; + _balances.insert(from, newBalance); + } + + if (!Utils_isKeyOrAddressZero(to)) { + if (!_balances.member(to)) { + _balances.insert(to, 0); + } + const newBalance = _balances.lookup(to) + 1 as Uint<128>; + _balances.insert(to, newBalance); + } + + _owners.insert(tokenId, to); + + return from; + } +} \ No newline at end of file From 576f64af160118cca43be8447887ccbaa88eed19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 19:55:45 -0400 Subject: [PATCH 194/282] fmt Utils --- contracts/utils/src/Utils.compact | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index 802416a1..21a04925 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -25,11 +25,11 @@ module Utils { return right(default) == keyOrAddress; } } - + /** * @description Returns whether `key` is the zero address. * - * @param {ZswapCoinPublicKey} key - A ZswapCoinPublicKey + * @param {ZswapCoinPublicKey} key - A ZswapCoinPublicKey * @return {Boolean} - Returns true if `key` is zero. */ export pure circuit isKeyZero(key: ZswapCoinPublicKey): Boolean { From 11bc82120d5ecdaac2e55c516506bc8773b833a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 20:00:52 -0400 Subject: [PATCH 195/282] Add test --- contracts/utils/src/test/utils.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 1e415546..4b8c73b4 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -54,6 +54,12 @@ describe('Utils', () => { contract.isKeyOrAddressEqual(SOME_CONTRACT, OTHER_CONTRACT), ).toBeFalsy(); }); + + it('should return false for two different address types of equal value', () => { + expect( + contract.isKeyOrAddressEqual(contractUtils.ZERO_KEY, contractUtils.ZERO_ADDRESS), + ).toBeFalsy(); + }); }); describe('isKeyZero', () => { From 259b90adaa64744dee2364d198b34965beecdab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 20:29:34 -0400 Subject: [PATCH 196/282] Rename TOKENID, create NON_EXISTENT_TOKEN, reword tests for consistency --- .../src/test/nonFungibleToken.test.ts | 708 +++++++++--------- 1 file changed, 355 insertions(+), 353 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index c2edbc86..be5bd31c 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -3,18 +3,20 @@ import { beforeEach, describe, expect, it } from 'vitest'; import { NonFungibleTokenSimulator } from './simulators/NonFungibleTokenSimulator.js'; import { UninitializedNonFungibleTokenSimulator } from './simulators/UninitializedNonFungibleTokenSimulator.js'; import { + ZERO_KEY, createEitherTestContractAddress, createEitherTestUser, - ZERO_KEY, } from './utils/address.js'; const SOME_STRING = 'https://openzeppelin.example'; - const NAME = 'NAME'; const SYMBOL = 'SYMBOL'; const EMPTY_STRING = ''; -const TOKENID: bigint = BigInt(1); +const TOKENID_1: bigint = BigInt(1); +const TOKENID_2: bigint = BigInt(2); +const TOKENID_3: bigint = BigInt(3); +const NON_EXISTENT_TOKEN: bigint = BigInt(0xdead); const AMOUNT: bigint = BigInt(1); const OWNER = String(Buffer.from('OWNER', 'ascii').toString('hex')).padStart( @@ -89,192 +91,192 @@ describe('NonFungibleToken', () => { }); it('should return correct balance for multiple tokens', () => { - token._mint(Z_OWNER, TOKENID); - token._mint(Z_OWNER, TOKENID + 1n); - token._mint(Z_OWNER, TOKENID + 2n); + token._mint(Z_OWNER, TOKENID_1); + token._mint(Z_OWNER, TOKENID_2); + token._mint(Z_OWNER, TOKENID_3); expect(token.balanceOf(Z_OWNER)).toEqual(3n); }); it('should return correct balance after burning multiple tokens', () => { - token._mint(Z_OWNER, TOKENID); - token._mint(Z_OWNER, TOKENID + 1n); - token._mint(Z_OWNER, TOKENID + 2n); - token._burn(TOKENID); - token._burn(TOKENID + 1n); + token._mint(Z_OWNER, TOKENID_1); + token._mint(Z_OWNER, TOKENID_2); + token._mint(Z_OWNER, TOKENID_3); + token._burn(TOKENID_1); + token._burn(TOKENID_2); expect(token.balanceOf(Z_OWNER)).toEqual(1n); }); it('should return correct balance after transferring multiple tokens', () => { - token._mint(Z_OWNER, TOKENID); - token._mint(Z_OWNER, TOKENID + 1n); - token._mint(Z_OWNER, TOKENID + 2n); - token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID); - token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID + 1n); + token._mint(Z_OWNER, TOKENID_1); + token._mint(Z_OWNER, TOKENID_2); + token._mint(Z_OWNER, TOKENID_3); + token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID_1); + token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID_2); expect(token.balanceOf(Z_OWNER)).toEqual(1n); expect(token.balanceOf(Z_SPENDER)).toEqual(2n); }); }); describe('ownerOf', () => { - it('should throw if tokenId does not exist', () => { + it('should throw if token does not exist', () => { expect(() => { - token.ownerOf(TOKENID); + token.ownerOf(NON_EXISTENT_TOKEN); }).toThrow('NonFungibleToken: Nonexistent Token'); }); - it('should throw if tokenId has been burned', () => { - token._mint(Z_OWNER, TOKENID); - token._burn(TOKENID); + it('should throw if token has been burned', () => { + token._mint(Z_OWNER, TOKENID_1); + token._burn(TOKENID_1); expect(() => { - token.ownerOf(TOKENID); + token.ownerOf(TOKENID_1); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should return owner of token if it exists', () => { - token._mint(Z_OWNER, TOKENID); - expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + token._mint(Z_OWNER, TOKENID_1); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); }); it('should return correct owner for multiple tokens', () => { - token._mint(Z_OWNER, TOKENID); - token._mint(Z_OWNER, TOKENID + 1n); - token._mint(Z_OWNER, TOKENID + 2n); - expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); - expect(token.ownerOf(TOKENID + 1n)).toEqual(Z_OWNER); - expect(token.ownerOf(TOKENID + 2n)).toEqual(Z_OWNER); + token._mint(Z_OWNER, TOKENID_1); + token._mint(Z_OWNER, TOKENID_2); + token._mint(Z_OWNER, TOKENID_3); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); + expect(token.ownerOf(TOKENID_2)).toEqual(Z_OWNER); + expect(token.ownerOf(TOKENID_3)).toEqual(Z_OWNER); }); it('should return correct owner after multiple transfers', () => { - token._mint(Z_OWNER, TOKENID); - token._mint(Z_OWNER, TOKENID + 1n); - token._transfer(Z_OWNER, Z_SPENDER, TOKENID); - token._transfer(Z_OWNER, Z_OTHER, TOKENID + 1n); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); - expect(token.ownerOf(TOKENID + 1n)).toEqual(Z_OTHER); + token._mint(Z_OWNER, TOKENID_1); + token._mint(Z_OWNER, TOKENID_2); + token._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); + token._transfer(Z_OWNER, Z_OTHER, TOKENID_2); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID_2)).toEqual(Z_OTHER); }); it('should return correct owner after multiple burns and mints', () => { - token._mint(Z_OWNER, TOKENID); - token._burn(TOKENID); - token._mint(Z_SPENDER, TOKENID); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + token._mint(Z_OWNER, TOKENID_1); + token._burn(TOKENID_1); + token._mint(Z_SPENDER, TOKENID_1); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); }); describe('tokenURI', () => { it('should throw if token does not exist', () => { expect(() => { - token.tokenURI(TOKENID); + token.tokenURI(NON_EXISTENT_TOKEN); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should return none if tokenURI set as default value', () => { - token._mint(Z_OWNER, TOKENID); - token._setTokenURI(TOKENID, EMPTY_STRING); - expect(token.tokenURI(TOKENID)).toEqual(EMPTY_STRING); + token._mint(Z_OWNER, TOKENID_1); + token._setTokenURI(TOKENID_1, EMPTY_STRING); + expect(token.tokenURI(TOKENID_1)).toEqual(EMPTY_STRING); }); it('should return some string if tokenURI is set', () => { - token._mint(Z_OWNER, TOKENID); - token._setTokenURI(TOKENID, SOME_STRING); - expect(token.tokenURI(TOKENID)).toEqual(SOME_STRING); + token._mint(Z_OWNER, TOKENID_1); + token._setTokenURI(TOKENID_1, SOME_STRING); + expect(token.tokenURI(TOKENID_1)).toEqual(SOME_STRING); }); it('should return empty string tokenURI', () => { - token._mint(Z_OWNER, TOKENID); - token._setTokenURI(TOKENID, ''); - expect(token.tokenURI(TOKENID)).toEqual(''); + token._mint(Z_OWNER, TOKENID_1); + token._setTokenURI(TOKENID_1, ''); + expect(token.tokenURI(TOKENID_1)).toEqual(''); }); it('should return very long tokenURI', () => { const longURI = 'A'.repeat(1000); - token._mint(Z_OWNER, TOKENID); - token._setTokenURI(TOKENID, longURI); - expect(token.tokenURI(TOKENID)).toEqual(longURI); + token._mint(Z_OWNER, TOKENID_1); + token._setTokenURI(TOKENID_1, longURI); + expect(token.tokenURI(TOKENID_1)).toEqual(longURI); }); it('should return tokenURI with special characters', () => { const specialURI = '!@#$%^&*()_+'; - token._mint(Z_OWNER, TOKENID); - token._setTokenURI(TOKENID, specialURI); - expect(token.tokenURI(TOKENID)).toEqual(specialURI); + token._mint(Z_OWNER, TOKENID_1); + token._setTokenURI(TOKENID_1, specialURI); + expect(token.tokenURI(TOKENID_1)).toEqual(specialURI); }); it('should update tokenURI multiple times', () => { - token._mint(Z_OWNER, TOKENID); - token._setTokenURI(TOKENID, 'URI1'); - token._setTokenURI(TOKENID, 'URI2'); - token._setTokenURI(TOKENID, 'URI3'); - expect(token.tokenURI(TOKENID)).toEqual('URI3'); + token._mint(Z_OWNER, TOKENID_1); + token._setTokenURI(TOKENID_1, 'URI1'); + token._setTokenURI(TOKENID_1, 'URI2'); + token._setTokenURI(TOKENID_1, 'URI3'); + expect(token.tokenURI(TOKENID_1)).toEqual('URI3'); }); it('should maintain tokenURI after token transfer', () => { - token._mint(Z_OWNER, TOKENID); - token._setTokenURI(TOKENID, SOME_STRING); - token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID); - expect(token.tokenURI(TOKENID)).toEqual(SOME_STRING); + token._mint(Z_OWNER, TOKENID_1); + token._setTokenURI(TOKENID_1, SOME_STRING); + token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID_1); + expect(token.tokenURI(TOKENID_1)).toEqual(SOME_STRING); }); }); describe('approve', () => { beforeEach(() => { - token._mint(Z_OWNER, TOKENID); - expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + token._mint(Z_OWNER, TOKENID_1); + expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); it('should throw if not owner', () => { _caller = UNAUTHORIZED; expect(() => { - token.approve(Z_SPENDER, TOKENID, _caller); + token.approve(Z_SPENDER, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Invalid Approver'); }); it('should approve spender', () => { _caller = OWNER; - token.approve(Z_SPENDER, TOKENID, _caller); - expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + token.approve(Z_SPENDER, TOKENID_1, _caller); + expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); it('should allow operator to approve', () => { _caller = OWNER; token.setApprovalForAll(Z_SPENDER, true, _caller); _caller = SPENDER; - token.approve(Z_OTHER, TOKENID, _caller); - expect(token.getApproved(TOKENID)).toEqual(Z_OTHER); + token.approve(Z_OTHER, TOKENID_1, _caller); + expect(token.getApproved(TOKENID_1)).toEqual(Z_OTHER); }); - it('spender approved for only TOKENID should not be able to approve', () => { + it('spender approved for only TOKENID_1 should not be able to approve', () => { _caller = OWNER; - token.approve(Z_SPENDER, TOKENID, _caller); + token.approve(Z_SPENDER, TOKENID_1, _caller); _caller = SPENDER; expect(() => { - token.approve(Z_OTHER, TOKENID, _caller); + token.approve(Z_OTHER, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Invalid Approver'); }); it('should approve same address multiple times', () => { _caller = OWNER; - token.approve(Z_SPENDER, TOKENID, _caller); - token.approve(Z_SPENDER, TOKENID, _caller); - expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + token.approve(Z_SPENDER, TOKENID_1, _caller); + token.approve(Z_SPENDER, TOKENID_1, _caller); + expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); it('should approve after token transfer', () => { _caller = OWNER; - token._transfer(Z_OWNER, Z_SPENDER, TOKENID); + token._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); _caller = SPENDER; - token.approve(Z_OTHER, TOKENID, _caller); - expect(token.getApproved(TOKENID)).toEqual(Z_OTHER); + token.approve(Z_OTHER, TOKENID_1, _caller); + expect(token.getApproved(TOKENID_1)).toEqual(Z_OTHER); }); it('should approve after token burn and remint', () => { _caller = OWNER; - token._burn(TOKENID); - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, _caller); - expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + token._burn(TOKENID_1); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, _caller); + expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); it('should approve with very long token ID', () => { @@ -287,36 +289,36 @@ describe('NonFungibleToken', () => { }); describe('getApproved', () => { - it('should throw if tokenId does not exist', () => { + it('should throw if token does not exist', () => { expect(() => { - token.getApproved(TOKENID); + token.getApproved(NON_EXISTENT_TOKEN); }).toThrow('NonFungibleToken: Nonexistent Token'); }); - it('should throw if tokenId has been burned', () => { - token._mint(Z_OWNER, TOKENID); - token._burn(TOKENID); + it('should throw if token has been burned', () => { + token._mint(Z_OWNER, TOKENID_1); + token._burn(TOKENID_1); expect(() => { - token.getApproved(TOKENID); + token.getApproved(TOKENID_1); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should get current approved spender', () => { - token._mint(Z_OWNER, TOKENID); - token.approve(Z_OWNER, TOKENID); - expect(token.getApproved(TOKENID)).toEqual(Z_OWNER); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_OWNER, TOKENID_1); + expect(token.getApproved(TOKENID_1)).toEqual(Z_OWNER); }); it('should return zero key if approval not set', () => { - token._mint(Z_OWNER, TOKENID); - expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + token._mint(Z_OWNER, TOKENID_1); + expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); }); describe('setApprovalForAll', () => { it('should not approve zero address', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { token.setApprovalForAll(ZERO_KEY, true, _caller); }).toThrow('NonFungibleToken: Invalid Operator'); @@ -324,7 +326,7 @@ describe('NonFungibleToken', () => { it('should approve operator for all tokens', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, OWNER); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); @@ -332,24 +334,24 @@ describe('NonFungibleToken', () => { it('spender should manage all tokens', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token._mint(Z_OWNER, TOKENID + 1n); - token._mint(Z_OWNER, TOKENID + 2n); + token._mint(Z_OWNER, TOKENID_1); + token._mint(Z_OWNER, TOKENID_2); + token._mint(Z_OWNER, TOKENID_3); token.setApprovalForAll(Z_SPENDER, true, OWNER); - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, SPENDER); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, SPENDER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); - token.approve(Z_OTHER, TOKENID + 1n, SPENDER); - expect(token.getApproved(TOKENID + 1n)).toEqual(Z_OTHER); + token.approve(Z_OTHER, TOKENID_2, SPENDER); + expect(token.getApproved(TOKENID_2)).toEqual(Z_OTHER); - token.approve(Z_SPENDER, TOKENID + 2n, SPENDER); - expect(token.getApproved(TOKENID + 2n)).toEqual(Z_SPENDER); + token.approve(Z_SPENDER, TOKENID_3, SPENDER); + expect(token.getApproved(TOKENID_3)).toEqual(Z_SPENDER); }); it('should revoke approval for all', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, _caller); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); @@ -358,13 +360,13 @@ describe('NonFungibleToken', () => { _caller = SPENDER; expect(() => { - token.approve(Z_SPENDER, TOKENID, _caller); + token.approve(Z_SPENDER, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Invalid Approver'); }); it('should set approval for all to same address multiple times', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, _caller); token.setApprovalForAll(Z_SPENDER, true, _caller); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); @@ -372,8 +374,8 @@ describe('NonFungibleToken', () => { it('should set approval for all after token transfer', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token._transfer(Z_OWNER, Z_SPENDER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); + token._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); _caller = SPENDER; token.setApprovalForAll(Z_OTHER, true, _caller); expect(token.isApprovedForAll(Z_SPENDER, Z_OTHER)).toBe(true); @@ -381,7 +383,7 @@ describe('NonFungibleToken', () => { it('should set approval for all with multiple operators', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, _caller); token.setApprovalForAll(Z_OTHER, true, _caller); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); @@ -404,7 +406,7 @@ describe('NonFungibleToken', () => { it('should return true if approval set', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, OWNER); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); }); @@ -412,110 +414,110 @@ describe('NonFungibleToken', () => { describe('transferFrom', () => { it('should not transfer to ContractAddress', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token.transferFrom(Z_OWNER, SOME_CONTRACT, TOKENID); + token.transferFrom(Z_OWNER, SOME_CONTRACT, TOKENID_1); }).toThrow('NonFungibleToken: Unsafe Transfer'); }); it('should not transfer to zero address', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token.transferFrom(Z_OWNER, ZERO_KEY, TOKENID); + token.transferFrom(Z_OWNER, ZERO_KEY, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Receiver'); }); it('should not transfer from zero address', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token.transferFrom(ZERO_KEY, Z_SPENDER, TOKENID); + token.transferFrom(ZERO_KEY, Z_SPENDER, TOKENID_1); }).toThrow('NonFungibleToken: Incorrect Owner'); }); it('should not transfer from unauthorized', () => { _caller = SPENDER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Insufficient Approval'); }); it('should not transfer token that has not been minted', () => { _caller = OWNER; expect(() => { - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should transfer token via approved operator', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, OWNER); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, OWNER); _caller = SPENDER; - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); it('should transfer token via approvedForAll operator', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, OWNER); _caller = SPENDER; - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); it('should allow transfer to same address', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token.transferFrom(Z_OWNER, Z_OWNER, TOKENID, _caller); + token.transferFrom(Z_OWNER, Z_OWNER, TOKENID_1, _caller); }).not.toThrow(); - expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); expect(token.balanceOf(Z_OWNER)).toEqual(1n); }); it('should not transfer after approval revocation', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, _caller); - token.approve(ZERO_KEY, TOKENID, _caller); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, _caller); + token.approve(ZERO_KEY, TOKENID_1, _caller); _caller = SPENDER; expect(() => { - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Insufficient Approval'); }); it('should not transfer after approval for all revocation', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, _caller); token.setApprovalForAll(Z_SPENDER, false, _caller); _caller = SPENDER; expect(() => { - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Insufficient Approval'); }); it('should transfer multiple tokens in sequence', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token._mint(Z_OWNER, TOKENID + 1n); - token._mint(Z_OWNER, TOKENID + 2n); - token.approve(Z_SPENDER, TOKENID, _caller); - token.approve(Z_SPENDER, TOKENID + 1n, _caller); - token.approve(Z_SPENDER, TOKENID + 2n, _caller); + token._mint(Z_OWNER, TOKENID_1); + token._mint(Z_OWNER, TOKENID_2); + token._mint(Z_OWNER, TOKENID_3); + token.approve(Z_SPENDER, TOKENID_1, _caller); + token.approve(Z_SPENDER, TOKENID_2, _caller); + token.approve(Z_SPENDER, TOKENID_3, _caller); _caller = SPENDER; - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID + 1n, _caller); - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID + 2n, _caller); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_2, _caller); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_3, _caller); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); - expect(token.ownerOf(TOKENID + 1n)).toEqual(Z_SPENDER); - expect(token.ownerOf(TOKENID + 2n)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID_2)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID_3)).toEqual(Z_SPENDER); }); it('should transfer with very long token IDs', () => { @@ -531,122 +533,122 @@ describe('NonFungibleToken', () => { it('should revoke approval after transferFrom', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, _caller); - token.transferFrom(Z_OWNER, Z_OTHER, TOKENID, _caller); - expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, _caller); + token.transferFrom(Z_OWNER, Z_OTHER, TOKENID_1, _caller); + expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); }); describe('_requireOwned', () => { it('should throw if token has not been minted', () => { expect(() => { - token._requireOwned(TOKENID); + token._requireOwned(TOKENID_1); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should throw if token has been burned', () => { - token._mint(Z_OWNER, TOKENID); - token._burn(TOKENID); + token._mint(Z_OWNER, TOKENID_1); + token._burn(TOKENID_1); expect(() => { - token._requireOwned(TOKENID); + token._requireOwned(TOKENID_1); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should return correct owner', () => { - token._mint(Z_OWNER, TOKENID); - expect(token._requireOwned(TOKENID)).toEqual(Z_OWNER); + token._mint(Z_OWNER, TOKENID_1); + expect(token._requireOwned(TOKENID_1)).toEqual(Z_OWNER); }); }); describe('_ownerOf', () => { it('should return zero address if token does not exist', () => { - expect(token._ownerOf(TOKENID)).toEqual(ZERO_KEY); + expect(token._ownerOf(NON_EXISTENT_TOKEN)).toEqual(ZERO_KEY); }); it('should return owner of token', () => { - token._mint(Z_OWNER, TOKENID); - expect(token._ownerOf(TOKENID)).toEqual(Z_OWNER); + token._mint(Z_OWNER, TOKENID_1); + expect(token._ownerOf(TOKENID_1)).toEqual(Z_OWNER); }); }); describe('_update', () => { it('should transfer token and clear approvals', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_OTHER, TOKENID, _caller); - const prevOwner = token._update(Z_SPENDER, TOKENID, ZERO_KEY); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_OTHER, TOKENID_1, _caller); + const prevOwner = token._update(Z_SPENDER, TOKENID_1, ZERO_KEY); expect(prevOwner).toEqual(Z_OWNER); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); expect(token.balanceOf(Z_OWNER)).toEqual(0n); expect(token.balanceOf(Z_SPENDER)).toEqual(1n); - expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); it('should mint a token', () => { - const prevOwner = token._update(Z_OWNER, TOKENID, ZERO_KEY); + const prevOwner = token._update(Z_OWNER, TOKENID_1, ZERO_KEY); expect(prevOwner).toEqual(ZERO_KEY); - expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); expect(token.balanceOf(Z_OWNER)).toEqual(1n); }); it('should burn a token', () => { - token._mint(Z_OWNER, TOKENID); - const prevOwner = token._update(ZERO_KEY, TOKENID, Z_OWNER); + token._mint(Z_OWNER, TOKENID_1); + const prevOwner = token._update(ZERO_KEY, TOKENID_1, Z_OWNER); expect(prevOwner).toEqual(Z_OWNER); expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token._ownerOf(TOKENID)).toEqual(ZERO_KEY); + expect(token._ownerOf(TOKENID_1)).toEqual(ZERO_KEY); }); it('should transfer if auth is authorized', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, _caller); - const prevOwner = token._update(Z_SPENDER, TOKENID, Z_SPENDER); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, _caller); + const prevOwner = token._update(Z_SPENDER, TOKENID_1, Z_SPENDER); expect(prevOwner).toEqual(Z_OWNER); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); expect(token.balanceOf(Z_OWNER)).toEqual(0n); expect(token.balanceOf(Z_SPENDER)).toEqual(1n); }); it('should transfer if auth is authorized for all', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, _caller); - const prevOwner = token._update(Z_SPENDER, TOKENID, Z_SPENDER); + const prevOwner = token._update(Z_SPENDER, TOKENID_1, Z_SPENDER); expect(prevOwner).toEqual(Z_OWNER); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); expect(token.balanceOf(Z_OWNER)).toEqual(0n); expect(token.balanceOf(Z_SPENDER)).toEqual(1n); }); it('should throw if auth is not authorized', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._update(Z_SPENDER, TOKENID, Z_SPENDER); + token._update(Z_SPENDER, TOKENID_1, Z_SPENDER); }).toThrow('NonFungibleToken: Insufficient Approval'); }); it('should update multiple tokens in sequence', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token._mint(Z_OWNER, TOKENID + 1n); - token._mint(Z_OWNER, TOKENID + 2n); - token.approve(Z_SPENDER, TOKENID, _caller); - token.approve(Z_SPENDER, TOKENID + 1n, _caller); - token.approve(Z_SPENDER, TOKENID + 2n, _caller); + token._mint(Z_OWNER, TOKENID_1); + token._mint(Z_OWNER, TOKENID_2); + token._mint(Z_OWNER, TOKENID_3); + token.approve(Z_SPENDER, TOKENID_1, _caller); + token.approve(Z_SPENDER, TOKENID_2, _caller); + token.approve(Z_SPENDER, TOKENID_3, _caller); - token._update(Z_SPENDER, TOKENID, Z_SPENDER); - token._update(Z_SPENDER, TOKENID + 1n, Z_SPENDER); - token._update(Z_SPENDER, TOKENID + 2n, Z_SPENDER); + token._update(Z_SPENDER, TOKENID_1, Z_SPENDER); + token._update(Z_SPENDER, TOKENID_2, Z_SPENDER); + token._update(Z_SPENDER, TOKENID_3, Z_SPENDER); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); - expect(token.ownerOf(TOKENID + 1n)).toEqual(Z_SPENDER); - expect(token.ownerOf(TOKENID + 2n)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID_2)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID_3)).toEqual(Z_SPENDER); }); it('should update with very long token IDs', () => { @@ -660,65 +662,65 @@ describe('NonFungibleToken', () => { it('should update after multiple transfers', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token._transfer(Z_OWNER, Z_SPENDER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); + token._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); _caller = SPENDER; - token.approve(Z_OTHER, TOKENID, _caller); - token._update(Z_OTHER, TOKENID, Z_OTHER); - expect(token.ownerOf(TOKENID)).toEqual(Z_OTHER); + token.approve(Z_OTHER, TOKENID_1, _caller); + token._update(Z_OTHER, TOKENID_1, Z_OTHER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_OTHER); }); it('should update after multiple burns', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token._burn(TOKENID); - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, _caller); - token._update(Z_SPENDER, TOKENID, Z_SPENDER); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + token._mint(Z_OWNER, TOKENID_1); + token._burn(TOKENID_1); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, _caller); + token._update(Z_SPENDER, TOKENID_1, Z_SPENDER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); }); describe('_approve', () => { it('should approve if auth is owner', () => { - token._mint(Z_OWNER, TOKENID); - token._approve(Z_SPENDER, TOKENID, Z_OWNER); - expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + token._mint(Z_OWNER, TOKENID_1); + token._approve(Z_SPENDER, TOKENID_1, Z_OWNER); + expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); it('should approve if auth is approved for all', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, _caller); - token._approve(Z_SPENDER, TOKENID, Z_SPENDER); - expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + token._approve(Z_SPENDER, TOKENID_1, Z_SPENDER); + expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); it('should throw if auth is unauthorized', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._approve(Z_SPENDER, TOKENID, Z_SPENDER); + token._approve(Z_SPENDER, TOKENID_1, Z_SPENDER); }).toThrow('NonFungibleToken: Invalid Approver'); }); it('should approve if auth is zero address', () => { - token._mint(Z_OWNER, TOKENID); - token._approve(Z_SPENDER, TOKENID, ZERO_KEY); - expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + token._mint(Z_OWNER, TOKENID_1); + token._approve(Z_SPENDER, TOKENID_1, ZERO_KEY); + expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); }); describe('_checkAuthorized', () => { it('should throw if token not minted', () => { expect(() => { - token._checkAuthorized(ZERO_KEY, Z_OWNER, TOKENID); + token._checkAuthorized(ZERO_KEY, Z_OWNER, TOKENID_1); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should throw if spender does not have approval', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._checkAuthorized(Z_OWNER, Z_SPENDER, TOKENID); + token._checkAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1); }).toThrow('NonFungibleToken: Insufficient Approval'); }); }); @@ -726,51 +728,51 @@ describe('NonFungibleToken', () => { describe('_isAuthorized', () => { it('should return true if spender is authorized', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, _caller); - expect(token._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID)).toBe(true); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, _caller); + expect(token._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1)).toBe(true); }); it('should return true if spender is authorized for all', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, _caller); - expect(token._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID)).toBe(true); + expect(token._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1)).toBe(true); }); it('should return true if spender is owner', () => { - token._mint(Z_OWNER, TOKENID); - expect(token._isAuthorized(Z_OWNER, Z_OWNER, TOKENID)).toBe(true); + token._mint(Z_OWNER, TOKENID_1); + expect(token._isAuthorized(Z_OWNER, Z_OWNER, TOKENID_1)).toBe(true); }); it('should return false if spender is zero address', () => { - expect(token._isAuthorized(Z_OWNER, ZERO_KEY, TOKENID)).toBe(false); + expect(token._isAuthorized(Z_OWNER, ZERO_KEY, TOKENID_1)).toBe(false); }); }); describe('_getApproved', () => { it('should return zero address if token is not minted', () => { - expect(token._getApproved(TOKENID)).toEqual(ZERO_KEY); + expect(token._getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); it('should return approved address', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, _caller); - expect(token._getApproved(TOKENID)).toEqual(Z_SPENDER); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, _caller); + expect(token._getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); }); describe('_setApprovalForAll', () => { it('should approve operator', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token._setApprovalForAll(Z_OWNER, Z_SPENDER, true); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); }); it('should revoke operator approval', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, _caller); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); @@ -788,36 +790,36 @@ describe('NonFungibleToken', () => { describe('_mint', () => { it('should not mint to ContractAddress', () => { expect(() => { - token._mint(SOME_CONTRACT, TOKENID); + token._mint(SOME_CONTRACT, TOKENID_1); }).toThrow('NonFungibleToken: Unsafe Transfer'); }); it('should not mint to zero address', () => { expect(() => { - token._mint(ZERO_KEY, TOKENID); + token._mint(ZERO_KEY, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Receiver'); }); it('should not mint a token that already exists', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Sender'); }); it('should mint token', () => { - token._mint(Z_OWNER, TOKENID); - expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + token._mint(Z_OWNER, TOKENID_1); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); expect(token.balanceOf(Z_OWNER)).toEqual(1n); - token._mint(Z_OWNER, TOKENID + 1n); - token._mint(Z_OWNER, TOKENID + 2n); + token._mint(Z_OWNER, TOKENID_2); + token._mint(Z_OWNER, TOKENID_3); expect(token.balanceOf(Z_OWNER)).toEqual(3n); }); it('should mint multiple tokens in sequence', () => { for (let i = 0; i < 10; i++) { - token._mint(Z_OWNER, TOKENID + BigInt(i)); + token._mint(Z_OWNER, TOKENID_1 + BigInt(i)); } expect(token.balanceOf(Z_OWNER)).toEqual(10n); }); @@ -829,52 +831,52 @@ describe('NonFungibleToken', () => { }); it('should mint after burning', () => { - token._mint(Z_OWNER, TOKENID); - token._burn(TOKENID); - token._mint(Z_OWNER, TOKENID); - expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + token._mint(Z_OWNER, TOKENID_1); + token._burn(TOKENID_1); + token._mint(Z_OWNER, TOKENID_1); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); }); it('should mint with special characters in metadata', () => { - token._mint(Z_OWNER, TOKENID); - token._setTokenURI(TOKENID, '!@#$%^&*()_+'); - expect(token.tokenURI(TOKENID)).toEqual('!@#$%^&*()_+'); + token._mint(Z_OWNER, TOKENID_1); + token._setTokenURI(TOKENID_1, '!@#$%^&*()_+'); + expect(token.tokenURI(TOKENID_1)).toEqual('!@#$%^&*()_+'); }); }); describe('_burn', () => { it('should burn token', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(token.balanceOf(Z_OWNER)).toEqual(1n); - token._burn(TOKENID); - expect(token._ownerOf(TOKENID)).toEqual(ZERO_KEY); + token._burn(TOKENID_1); + expect(token._ownerOf(TOKENID_1)).toEqual(ZERO_KEY); expect(token.balanceOf(Z_OWNER)).toEqual(0n); }); it('should not burn a token that does not exist', () => { expect(() => { - token._burn(TOKENID); + token._burn(TOKENID_1); }).toThrow('NonFungibleToken: Invalid Sender'); }); it('should clear approval when token is burned', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, _caller); - expect(token.getApproved(TOKENID)).toEqual(Z_SPENDER); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, _caller); + expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); - token._burn(TOKENID); - expect(token._getApproved(TOKENID)).toEqual(ZERO_KEY); + token._burn(TOKENID_1); + expect(token._getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); it('should burn multiple tokens in sequence', () => { - token._mint(Z_OWNER, TOKENID); - token._mint(Z_OWNER, TOKENID + 1n); - token._mint(Z_OWNER, TOKENID + 2n); - token._burn(TOKENID); - token._burn(TOKENID + 1n); - token._burn(TOKENID + 2n); + token._mint(Z_OWNER, TOKENID_1); + token._mint(Z_OWNER, TOKENID_2); + token._mint(Z_OWNER, TOKENID_3); + token._burn(TOKENID_1); + token._burn(TOKENID_2); + token._burn(TOKENID_3); expect(token.balanceOf(Z_OWNER)).toEqual(0n); }); @@ -886,226 +888,226 @@ describe('NonFungibleToken', () => { }); it('should burn after transfer', () => { - token._mint(Z_OWNER, TOKENID); - token._transfer(Z_OWNER, Z_SPENDER, TOKENID); - token._burn(TOKENID); - expect(token._ownerOf(TOKENID)).toEqual(ZERO_KEY); + token._mint(Z_OWNER, TOKENID_1); + token._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); + token._burn(TOKENID_1); + expect(token._ownerOf(TOKENID_1)).toEqual(ZERO_KEY); }); it('should burn after approval', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, _caller); - token._burn(TOKENID); - expect(token._ownerOf(TOKENID)).toEqual(ZERO_KEY); - expect(token._getApproved(TOKENID)).toEqual(ZERO_KEY); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, _caller); + token._burn(TOKENID_1); + expect(token._ownerOf(TOKENID_1)).toEqual(ZERO_KEY); + expect(token._getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); }); describe('_transfer', () => { it('should not transfer to ContractAddress', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._transfer(Z_OWNER, SOME_CONTRACT, TOKENID); + token._transfer(Z_OWNER, SOME_CONTRACT, TOKENID_1); }).toThrow('NonFungibleToken: Unsafe Transfer'); }); it('should transfer token', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(token.balanceOf(Z_OWNER)).toEqual(1n); expect(token.balanceOf(Z_SPENDER)).toEqual(0n); - expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); - token._transfer(Z_OWNER, Z_SPENDER, TOKENID); + token._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); expect(token.balanceOf(Z_OWNER)).toEqual(0n); expect(token.balanceOf(Z_SPENDER)).toEqual(1n); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); it('should not transfer to zero address', () => { expect(() => { - token._transfer(Z_OWNER, ZERO_KEY, TOKENID); + token._transfer(Z_OWNER, ZERO_KEY, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Receiver'); }); it('should throw if from does not own token', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._transfer(Z_SPENDER, Z_SPENDER, TOKENID); + token._transfer(Z_SPENDER, Z_SPENDER, TOKENID_1); }).toThrow('NonFungibleToken: Incorrect Owner'); }); it('should throw if token does not exist', () => { expect(() => { - token._transfer(Z_OWNER, Z_SPENDER, TOKENID); + token._transfer(Z_OWNER, Z_SPENDER, NON_EXISTENT_TOKEN); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should revoke approval after _transfer', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, _caller); - token._transfer(Z_OWNER, Z_OTHER, TOKENID); - expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, _caller); + token._transfer(Z_OWNER, Z_OTHER, TOKENID_1); + expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); }); describe('_setTokenURI', () => { it('should throw if token does not exist', () => { expect(() => { - token._setTokenURI(TOKENID, EMPTY_STRING); + token._setTokenURI(NON_EXISTENT_TOKEN, EMPTY_STRING); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should set tokenURI', () => { - token._mint(Z_OWNER, TOKENID); - token._setTokenURI(TOKENID, SOME_STRING); - expect(token.tokenURI(TOKENID)).toEqual(SOME_STRING); + token._mint(Z_OWNER, TOKENID_1); + token._setTokenURI(TOKENID_1, SOME_STRING); + expect(token.tokenURI(TOKENID_1)).toEqual(SOME_STRING); }); }); describe('_unsafeMint', () => { it('should mint to ContractAddress', () => { expect(() => { - token._unsafeMint(SOME_CONTRACT, TOKENID); + token._unsafeMint(SOME_CONTRACT, TOKENID_1); }).not.toThrow(); }); it('should not mint to zero address', () => { expect(() => { - token._unsafeMint(ZERO_KEY, TOKENID); + token._unsafeMint(ZERO_KEY, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Receiver'); }); it('should not mint a token that already exists', () => { - token._unsafeMint(Z_OWNER, TOKENID); + token._unsafeMint(Z_OWNER, TOKENID_1); expect(() => { - token._unsafeMint(Z_OWNER, TOKENID); + token._unsafeMint(Z_OWNER, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Sender'); }); it('should mint token to public key', () => { - token._unsafeMint(Z_OWNER, TOKENID); - expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + token._unsafeMint(Z_OWNER, TOKENID_1); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); expect(token.balanceOf(Z_OWNER)).toEqual(1n); - token._unsafeMint(Z_OWNER, TOKENID + 1n); - token._unsafeMint(Z_OWNER, TOKENID + 2n); + token._unsafeMint(Z_OWNER, TOKENID_2); + token._unsafeMint(Z_OWNER, TOKENID_3); expect(token.balanceOf(Z_OWNER)).toEqual(3n); }); }); describe('_unsafeTransfer', () => { it('should transfer to ContractAddress', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._unsafeTransfer(Z_OWNER, SOME_CONTRACT, TOKENID); + token._unsafeTransfer(Z_OWNER, SOME_CONTRACT, TOKENID_1); }).not.toThrow(); }); it('should transfer token to public key', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(token.balanceOf(Z_OWNER)).toEqual(1n); expect(token.balanceOf(Z_SPENDER)).toEqual(0n); - expect(token.ownerOf(TOKENID)).toEqual(Z_OWNER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); - token._unsafeTransfer(Z_OWNER, Z_SPENDER, TOKENID); + token._unsafeTransfer(Z_OWNER, Z_SPENDER, TOKENID_1); expect(token.balanceOf(Z_OWNER)).toEqual(0n); expect(token.balanceOf(Z_SPENDER)).toEqual(1n); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); it('should not transfer to zero address', () => { expect(() => { - token._unsafeTransfer(Z_OWNER, ZERO_KEY, TOKENID); + token._unsafeTransfer(Z_OWNER, ZERO_KEY, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Receiver'); }); it('should throw if from does not own token', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._unsafeTransfer(Z_SPENDER, Z_SPENDER, TOKENID); + token._unsafeTransfer(Z_SPENDER, Z_SPENDER, TOKENID_1); }).toThrow('NonFungibleToken: Incorrect Owner'); }); it('should throw if token does not exist', () => { expect(() => { - token._unsafeTransfer(Z_OWNER, Z_SPENDER, TOKENID); + token._unsafeTransfer(Z_OWNER, Z_SPENDER, NON_EXISTENT_TOKEN); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should revoke approval after _unsafeTransfer', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, _caller); - token._unsafeTransfer(Z_OWNER, Z_OTHER, TOKENID); - expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, _caller); + token._unsafeTransfer(Z_OWNER, Z_OTHER, TOKENID_1); + expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); }); describe('_unsafeTransferFrom', () => { it('should transfer to ContractAddress', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._unsafeTransferFrom(Z_OWNER, SOME_CONTRACT, TOKENID); + token._unsafeTransferFrom(Z_OWNER, SOME_CONTRACT, TOKENID_1); }).not.toThrow(); }); it('should not transfer to zero address', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._unsafeTransferFrom(Z_OWNER, ZERO_KEY, TOKENID); + token._unsafeTransferFrom(Z_OWNER, ZERO_KEY, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Receiver'); }); it('should not transfer from zero address', () => { - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._unsafeTransferFrom(ZERO_KEY, Z_SPENDER, TOKENID); + token._unsafeTransferFrom(ZERO_KEY, Z_SPENDER, TOKENID_1); }).toThrow('NonFungibleToken: Incorrect Owner'); }); it('unapproved operator should not transfer', () => { _caller = SPENDER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Insufficient Approval'); }); it('should not transfer token that has not been minted', () => { _caller = OWNER; expect(() => { - token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); + token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should transfer token via approved operator', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, OWNER); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, OWNER); _caller = SPENDER; - token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); it('should transfer token via approvedForAll operator', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); + token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, OWNER); _caller = SPENDER; - token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID, _caller); - expect(token.ownerOf(TOKENID)).toEqual(Z_SPENDER); + token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); it('should revoke approval after _unsafeTransferFrom', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID); - token.approve(Z_SPENDER, TOKENID, _caller); - token._unsafeTransferFrom(Z_OWNER, Z_OTHER, TOKENID, _caller); - expect(token.getApproved(TOKENID)).toEqual(ZERO_KEY); + token._mint(Z_OWNER, TOKENID_1); + token.approve(Z_SPENDER, TOKENID_1, _caller); + token._unsafeTransferFrom(Z_OWNER, Z_OTHER, TOKENID_1, _caller); + expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); }); }); @@ -1144,7 +1146,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('ownerOf', () => { it('should throw', () => { expect(() => { - uninitializedToken.ownerOf(TOKENID); + uninitializedToken.ownerOf(TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1152,7 +1154,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('tokenURI', () => { it('should throw', () => { expect(() => { - uninitializedToken.tokenURI(TOKENID); + uninitializedToken.tokenURI(TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1160,7 +1162,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('approve', () => { it('should throw', () => { expect(() => { - uninitializedToken.approve(Z_OWNER, TOKENID); + uninitializedToken.approve(Z_OWNER, TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1168,7 +1170,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('getApproved', () => { it('should throw', () => { expect(() => { - uninitializedToken.getApproved(TOKENID); + uninitializedToken.getApproved(TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1192,7 +1194,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('transferFrom', () => { it('should throw', () => { expect(() => { - uninitializedToken.transferFrom(Z_OWNER, Z_SPENDER, TOKENID); + uninitializedToken.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1200,7 +1202,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_requireOwned', () => { it('should throw', () => { expect(() => { - uninitializedToken._requireOwned(TOKENID); + uninitializedToken._requireOwned(TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1208,7 +1210,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_ownerOf', () => { it('should throw', () => { expect(() => { - uninitializedToken._ownerOf(TOKENID); + uninitializedToken._ownerOf(TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1216,7 +1218,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_update', () => { it('should throw', () => { expect(() => { - uninitializedToken._update(Z_OWNER, TOKENID, Z_SPENDER); + uninitializedToken._update(Z_OWNER, TOKENID_1, Z_SPENDER); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1224,7 +1226,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_approve', () => { it('should throw', () => { expect(() => { - uninitializedToken._approve(Z_OWNER, TOKENID, Z_SPENDER); + uninitializedToken._approve(Z_OWNER, TOKENID_1, Z_SPENDER); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1232,7 +1234,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_checkAuthorized', () => { it('should throw', () => { expect(() => { - uninitializedToken._checkAuthorized(Z_OWNER, Z_SPENDER, TOKENID); + uninitializedToken._checkAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1240,7 +1242,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_isAuthorized', () => { it('should throw', () => { expect(() => { - uninitializedToken._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID); + uninitializedToken._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1248,7 +1250,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_getApproved', () => { it('should throw', () => { expect(() => { - uninitializedToken._getApproved(TOKENID); + uninitializedToken._getApproved(TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1264,7 +1266,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_mint', () => { it('should throw', () => { expect(() => { - uninitializedToken._mint(Z_OWNER, TOKENID); + uninitializedToken._mint(Z_OWNER, TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1272,7 +1274,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_burn', () => { it('should throw', () => { expect(() => { - uninitializedToken._burn(TOKENID); + uninitializedToken._burn(TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1280,7 +1282,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_transfer', () => { it('should throw', () => { expect(() => { - uninitializedToken._transfer(Z_OWNER, Z_SPENDER, TOKENID); + uninitializedToken._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1288,7 +1290,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_setTokenURI', () => { it('should throw', () => { expect(() => { - uninitializedToken._setTokenURI(TOKENID, SOME_STRING); + uninitializedToken._setTokenURI(TOKENID_1, SOME_STRING); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1296,7 +1298,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_unsafeTransferFrom', () => { it('should throw', () => { expect(() => { - uninitializedToken._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID); + uninitializedToken._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1304,7 +1306,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_unsafeTransfer', () => { it('should throw', () => { expect(() => { - uninitializedToken._unsafeTransfer(Z_OWNER, Z_SPENDER, TOKENID); + uninitializedToken._unsafeTransfer(Z_OWNER, Z_SPENDER, TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); @@ -1312,7 +1314,7 @@ describe('Uninitialized NonFungibleToken', () => { describe('_unsafeMint', () => { it('should throw', () => { expect(() => { - uninitializedToken._unsafeMint(Z_OWNER, TOKENID); + uninitializedToken._unsafeMint(Z_OWNER, TOKENID_1); }).toThrow('Initializable: contract not initialized'); }); }); From 36406ed70fba19b47ba8070d889e6e0b57b300eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 20:29:43 -0400 Subject: [PATCH 197/282] fmt files --- .../simulators/NonFungibleTokenSimulator.ts | 639 ++++++++++++++++++ .../UninitializedNonFungibleTokenSimulator.ts | 13 +- contracts/utils/src/test/utils.test.ts | 5 +- 3 files changed, 650 insertions(+), 7 deletions(-) create mode 100644 contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts diff --git a/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts b/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts new file mode 100644 index 00000000..e0b730a7 --- /dev/null +++ b/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts @@ -0,0 +1,639 @@ +import { + type CircuitContext, + type CoinPublicKey, + type ContractState, + QueryContext, + constructorContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import { sampleContractAddress } from '@midnight-ntwrk/zswap'; +import { + type ContractAddress, + type Either, + type Ledger, + Contract as MockNonFungibleToken, + type ZswapCoinPublicKey, + ledger, +} from '../../artifacts/MockNonFungibleToken/contract/index.cjs'; // Combined imports +import { + type NonFungibleTokenPrivateState, + NonFungibleTokenWitnesses, +} from '../../witnesses/NonFungibleTokenWitnesses.js'; +import type { IContractSimulator } from '../types/test.js'; + +/** + * @description A simulator implementation of an nonFungibleToken contract for testing purposes. + * @template P - The private state type, fixed to NonFungibleTokenPrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class NonFungibleTokenSimulator + implements IContractSimulator +{ + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockNonFungibleToken; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor(name: string, symbol: string) { + this.contract = new MockNonFungibleToken( + NonFungibleTokenWitnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)), + name, + symbol, + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type NonFungibleTokenPrivateState. + */ + public getCurrentPrivateState(): NonFungibleTokenPrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + + /** + * @description Returns the token name. + * @returns The token name. + */ + public name(): string { + return this.contract.impureCircuits.name(this.circuitContext).result; + } + + /** + * @description Returns the symbol of the token. + * @returns The token name. + */ + public symbol(): string { + return this.contract.impureCircuits.symbol(this.circuitContext).result; + } + + /** + * @description Returns the number of tokens in `account`'s account. + * @param account The public key to query. + * @return The number of tokens in `account`'s account. + */ + public balanceOf( + account: Either, + ): bigint { + return this.contract.impureCircuits.balanceOf(this.circuitContext, account) + .result; + } + + /** + * @description Returns the owner of the `tokenId` token. + * @param tokenId The identifier for a token. + * @return The public key that owns the token. + */ + public ownerOf(tokenId: bigint): Either { + return this.contract.impureCircuits.ownerOf(this.circuitContext, tokenId) + .result; + } + + /** + * @description Returns the token URI for the given `tokenId`. + * @notice Since Midnight does not support native strings and string operations + * within the Compact language, concatenating a base URI + token ID is not possible + * like in other NFT implementations. Therefore, we propose the URI storage + * approach; whereby, NFTs may or may not have unique "base" URIs. + * It's up to the implementation to decide on how to handle this. + * @param tokenId The identifier for a token. + * @returns The token id's URI. + */ + public tokenURI(tokenId: bigint): string { + return this.contract.impureCircuits.tokenURI(this.circuitContext, tokenId) + .result; + } + + /** + * @description Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * @param to The account receiving the approval + * @param tokenId The token `to` may be permitted to transfer + * @return None. + */ + public approve( + to: Either, + tokenId: bigint, + sender?: CoinPublicKey, + ) { + const res = this.contract.impureCircuits.approve( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + to, + tokenId, + ); + + this.circuitContext = res.context; + } + + /** + * @description Returns the account approved for `tokenId` token. + * @param tokenId The token an account may be approved to manage + * @return The account approved to manage the token + */ + public getApproved( + tokenId: bigint, + ): Either { + return this.contract.impureCircuits.getApproved( + this.circuitContext, + tokenId, + ).result; + } + + /** + * @description Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the address zero. + * + * @param operator An operator to manage the caller's tokens + * @param approved A boolean determining if `operator` may manage all tokens of the caller + * @return None. + */ + public setApprovalForAll( + operator: Either, + approved: boolean, + sender?: CoinPublicKey, + ) { + const res = this.contract.impureCircuits.setApprovalForAll( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + operator, + approved, + ); + + this.circuitContext = res.context; + } + + /** + * @description Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * @param owner The owner of a token + * @param operator An account that may operate on `owner`'s tokens + * @return A boolean determining if `operator` is allowed to manage all of the tokens of `owner` + */ + public isApprovedForAll( + owner: Either, + operator: Either, + ): boolean { + return this.contract.impureCircuits.isApprovedForAll( + this.circuitContext, + owner, + operator, + ).result; + } + + /** + * @description Transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * @param {Either} from - The source account from which the token is being transfered + * @param {Either} to - The target account to transfer token to + * @param {TokenId} tokenId - The token being transfered + * @return {[]} - None. + */ + public transferFrom( + from: Either, + to: Either, + tokenId: bigint, + sender?: CoinPublicKey, + ) { + const res = this.contract.impureCircuits.transferFrom( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + from, + to, + tokenId, + ); + + this.circuitContext = res.context; + } + + /** + * @description Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). + * Returns the owner. + * + * Overrides to ownership logic should be done to {_ownerOf}. + * + * @param tokenId The token that should be owned + * @return The owner of `tokenId` + */ + public _requireOwned( + tokenId: bigint, + ): Either { + return this.contract.impureCircuits._requireOwned( + this.circuitContext, + tokenId, + ).result; + } + + /** + * @description Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist + * + * @param tokenId The target token of the owner query + * @return The owner of the token + */ + public _ownerOf( + tokenId: bigint, + ): Either { + return this.contract.impureCircuits._ownerOf(this.circuitContext, tokenId) + .result; + } + + /** + * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner + * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. + * + * The `auth` argument is optional. If the value passed is non 0, then this function will check that + * `auth` is either the owner of the token, or approved to operate on the token (by the owner). + * + * @param to The intended recipient of the token transfer + * @param tokenId The token being transfered + * @param auth An account authorized to transfer the token + * @return Owner of the token before it was transfered + */ + public _update( + to: Either, + tokenId: bigint, + auth: Either, + ): Either { + const res = this.contract.impureCircuits._update( + this.circuitContext, + to, + tokenId, + auth, + ); + + this.circuitContext = res.context; + return res.result; + } + + /** + * @description Approve `to` to operate on `tokenId` + * + * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is + * either the owner of the token, or approved to operate on all tokens held by this owner. + * + * @param to The target account to approve + * @param tokenId The token to approve + * @param auth An account authorized to operate on all tokens held by the owner the token + * @return None. + */ + public _approve( + to: Either, + tokenId: bigint, + auth: Either, + ) { + this.circuitContext = this.contract.impureCircuits._approve( + this.circuitContext, + to, + tokenId, + auth, + ).context; + } + + /** + * @description Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. + * Reverts if: + * - `spender` does not have approval from `owner` for `tokenId`. + * - `spender` does not have approval to manage all of `owner`'s assets. + * + * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this + * assumption. + * + * @param owner Owner of the token + * @param spender Account operating on `tokenId` + * @param tokenId The token to spend + * @return None. + */ + public _checkAuthorized( + owner: Either, + spender: Either, + tokenId: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._checkAuthorized( + this.circuitContext, + owner, + spender, + tokenId, + ).context; + } + + /** + * @description Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in + * particular (ignoring whether it is owned by `owner`). + * + * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this + * assumption. + * + * @param owner Owner of the token + * @param spender Account that wishes to spend `tokenId` + * @param tokenId Token to spend + * @return A boolean determining if `spender` may manage `tokenId` + */ + public _isAuthorized( + owner: Either, + spender: Either, + tokenId: bigint, + ): boolean { + return this.contract.impureCircuits._isAuthorized( + this.circuitContext, + owner, + spender, + tokenId, + ).result; + } + + /** + * @description Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. + * + * @param tokenId The token to query + * @return An account approved to spend `tokenId` + */ + public _getApproved( + tokenId: bigint, + ): Either { + return this.contract.impureCircuits._getApproved( + this.circuitContext, + tokenId, + ).result; + } + + /** + * @description Approve `operator` to operate on all of `owner` tokens + * + * Requirements: + * + * - operator can't be the address zero. + * + * @param owner Owner of a token + * @param operator The account to approve + * @param approved A boolean determining if `operator` may operate on all of `owner` tokens + * @return None. + */ + public _setApprovalForAll( + owner: Either, + operator: Either, + approved: boolean, + ) { + this.circuitContext = this.contract.impureCircuits._setApprovalForAll( + this.circuitContext, + owner, + operator, + approved, + ).context; + } + + /** + * @description Mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * @param to The account receiving `tokenId` + * @param tokenId The token to transfer + * @return None. + */ + public _mint( + to: Either, + tokenId: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._mint( + this.circuitContext, + to, + tokenId, + ).context; + } + + /** + * @description Destroys `tokenId`. + * The approval is cleared when the token is burned. + * This is an internal function that does not check if the sender is authorized to operate on the token. + * + * Requirements: + * + * - `tokenId` must exist. + * + * @param tokenId The token to burn + * @return None. + */ + public _burn(tokenId: bigint) { + this.circuitContext = this.contract.impureCircuits._burn( + this.circuitContext, + tokenId, + ).context; + } + + /** + * @description Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on own_public_key(). + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * @param from The source account of the token transfer + * @param to The target account of the token transfer + * @param tokenId The token to transfer + * @return None. + */ + public _transfer( + from: Either, + to: Either, + tokenId: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._transfer( + this.circuitContext, + from, + to, + tokenId, + ).context; + } + + /** + * @description Sets the the URI as `tokenURI` for the given `tokenId`. + * The `tokenId` must exist. + * + * @notice The URI for a given NFT is usually set when the NFT is minted. + * + * @param tokenId The identifier of the token. + * @param tokenURI The URI of `tokenId`. + * @return None + */ + public _setTokenURI(tokenId: bigint, tokenURI: string) { + this.circuitContext = this.contract.impureCircuits._setTokenURI( + this.circuitContext, + tokenId, + tokenURI, + ).context; + } + + /** + * @description Transfers `tokenId` token from `from` to `to`. It does NOT check if the recipient is a ContractAddress. + * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the + * ContractAddress + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * @param {Either} from - The source account from which the token is being transfered + * @param {Either} to - The target account to transfer token to + * @param {TokenId} tokenId - The token being transfered + * @return {[]} - None. + */ + public _unsafeTransferFrom( + from: Either, + to: Either, + tokenId: bigint, + sender?: CoinPublicKey, + ) { + const res = this.contract.impureCircuits._unsafeTransferFrom( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + from, + to, + tokenId, + ); + + this.circuitContext = res.context; + } + + /** + * @description Transfers `tokenId` from `from` to `to`. + * As opposed to {_unsafeTransferFrom}, this imposes no restrictions on own_public_key(). + * It does NOT check if the recipient is a ContractAddress. + * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the + * ContractAddress + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * @param {Either} from - The source account of the token transfer + * @param {Either} to - The target account of the token transfer + * @param {TokenId} tokenId - The token to transfer + * @return {[]} - None. + */ + public _unsafeTransfer( + from: Either, + to: Either, + tokenId: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._unsafeTransfer( + this.circuitContext, + from, + to, + tokenId, + ).context; + } + + /** + * @description Mints `tokenId` and transfers it to `to`. It does NOT check if the recipient is a ContractAddress. + * + * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts + * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the + * ContractAddress + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * @param {Either} to - The account receiving `tokenId` + * @param {TokenId} tokenId - The token to transfer + * @return {[]} - None. + */ + public _unsafeMint( + to: Either, + tokenId: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._unsafeMint( + this.circuitContext, + to, + tokenId, + ).context; + } +} diff --git a/contracts/nonFungibleToken/src/test/simulators/UninitializedNonFungibleTokenSimulator.ts b/contracts/nonFungibleToken/src/test/simulators/UninitializedNonFungibleTokenSimulator.ts index f4761427..c0a25152 100644 --- a/contracts/nonFungibleToken/src/test/simulators/UninitializedNonFungibleTokenSimulator.ts +++ b/contracts/nonFungibleToken/src/test/simulators/UninitializedNonFungibleTokenSimulator.ts @@ -8,11 +8,11 @@ import { } from '@midnight-ntwrk/compact-runtime'; import { sampleContractAddress } from '@midnight-ntwrk/zswap'; import { - type Ledger, - type Either, - type ZswapCoinPublicKey, type ContractAddress, + type Either, + type Ledger, Contract as MockUninitializedNonFungibleToken, + type ZswapCoinPublicKey, ledger, } from '../../artifacts/MockUninitializedNonFungibleToken/contract/index.cjs'; // Combined imports import { @@ -42,9 +42,10 @@ export class UninitializedNonFungibleTokenSimulator * @description Initializes the mock contract. */ constructor() { - this.contract = new MockUninitializedNonFungibleToken( - NonFungibleTokenWitnesses, - ); + this.contract = + new MockUninitializedNonFungibleToken( + NonFungibleTokenWitnesses, + ); const { currentPrivateState, currentContractState, diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 4b8c73b4..8feca5d1 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -57,7 +57,10 @@ describe('Utils', () => { it('should return false for two different address types of equal value', () => { expect( - contract.isKeyOrAddressEqual(contractUtils.ZERO_KEY, contractUtils.ZERO_ADDRESS), + contract.isKeyOrAddressEqual( + contractUtils.ZERO_KEY, + contractUtils.ZERO_ADDRESS, + ), ).toBeFalsy(); }); }); From 7e53fde318b58302ab888211b908442e94720d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 22:24:35 -0400 Subject: [PATCH 198/282] fmt file --- contracts/nonFungibleToken/src/NonFungibleToken.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index 87d9ea41..430e424f 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -584,7 +584,7 @@ module NonFungibleToken { * * @param {Either} owner - Owner of a token * @param {Either} operator - The account to approve - * @param {Boolean} approved - A boolean determining if `operator` may operate on all of `owner` tokens + * @param {Boolean} approved - A boolean determining if `operator` may operate on all of `owner` tokens * @return {[]} - None. */ export circuit _setApprovalForAll( From c6225037ab9f0be855410cbc533e8b88a3eefaa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 22:25:01 -0400 Subject: [PATCH 199/282] Update NonFungibleToken tests --- .../src/test/nonFungibleToken.test.ts | 91 ++++++++++--------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index be5bd31c..17fb4714 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -34,6 +34,7 @@ const Z_OWNER = createEitherTestUser('OWNER'); const Z_SPENDER = createEitherTestUser('SPENDER'); const Z_RECIPIENT = createEitherTestUser('RECIPIENT'); const Z_OTHER = createEitherTestUser('OTHER'); +const Z_UNAUTHORIZED = createEitherTestUser('UNAUTHORIZED'); const SOME_CONTRACT = createEitherTestContractAddress('CONTRACT'); let token: NonFungibleTokenSimulator; @@ -113,7 +114,7 @@ describe('NonFungibleToken', () => { token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID_1); token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID_2); expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_SPENDER)).toEqual(2n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(2n); }); }); @@ -170,7 +171,7 @@ describe('NonFungibleToken', () => { }).toThrow('NonFungibleToken: Nonexistent Token'); }); - it('should return none if tokenURI set as default value', () => { + it('should return the empty string if tokenURI set as default value', () => { token._mint(Z_OWNER, TOKENID_1); token._setTokenURI(TOKENID_1, EMPTY_STRING); expect(token.tokenURI(TOKENID_1)).toEqual(EMPTY_STRING); @@ -182,12 +183,6 @@ describe('NonFungibleToken', () => { expect(token.tokenURI(TOKENID_1)).toEqual(SOME_STRING); }); - it('should return empty string tokenURI', () => { - token._mint(Z_OWNER, TOKENID_1); - token._setTokenURI(TOKENID_1, ''); - expect(token.tokenURI(TOKENID_1)).toEqual(''); - }); - it('should return very long tokenURI', () => { const longURI = 'A'.repeat(1000); token._mint(Z_OWNER, TOKENID_1); @@ -289,6 +284,10 @@ describe('NonFungibleToken', () => { }); describe('getApproved', () => { + beforeEach(() => { + token._mint(Z_OWNER, TOKENID_1); + }); + it('should throw if token does not exist', () => { expect(() => { token.getApproved(NON_EXISTENT_TOKEN); @@ -296,7 +295,6 @@ describe('NonFungibleToken', () => { }); it('should throw if token has been burned', () => { - token._mint(Z_OWNER, TOKENID_1); token._burn(TOKENID_1); expect(() => { token.getApproved(TOKENID_1); @@ -304,13 +302,11 @@ describe('NonFungibleToken', () => { }); it('should get current approved spender', () => { - token._mint(Z_OWNER, TOKENID_1); token.approve(Z_OWNER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(Z_OWNER); }); it('should return zero key if approval not set', () => { - token._mint(Z_OWNER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); }); @@ -324,7 +320,7 @@ describe('NonFungibleToken', () => { }).toThrow('NonFungibleToken: Invalid Operator'); }); - it('should approve operator for all tokens', () => { + it('should set operator', () => { _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); @@ -332,20 +328,21 @@ describe('NonFungibleToken', () => { expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); }); - it('spender should manage all tokens', () => { + it('should allow operator to manage owner tokens', () => { _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); token._mint(Z_OWNER, TOKENID_2); token._mint(Z_OWNER, TOKENID_3); + token.setApprovalForAll(Z_SPENDER, true, _caller); - token.setApprovalForAll(Z_SPENDER, true, OWNER); - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, SPENDER); + _caller = SPENDER; + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); - token.approve(Z_OTHER, TOKENID_2, SPENDER); + token.approve(Z_OTHER, TOKENID_2, _caller); expect(token.getApproved(TOKENID_2)).toEqual(Z_OTHER); - token.approve(Z_SPENDER, TOKENID_3, SPENDER); + token.approve(Z_SPENDER, TOKENID_3, _caller); expect(token.getApproved(TOKENID_3)).toEqual(Z_SPENDER); }); @@ -376,6 +373,7 @@ describe('NonFungibleToken', () => { _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); token._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); + _caller = SPENDER; token.setApprovalForAll(Z_OTHER, true, _caller); expect(token.isApprovedForAll(Z_SPENDER, Z_OTHER)).toBe(true); @@ -413,45 +411,44 @@ describe('NonFungibleToken', () => { }); describe('transferFrom', () => { - it('should not transfer to ContractAddress', () => { + beforeEach(() => { token._mint(Z_OWNER, TOKENID_1); + }); + + it('should not transfer to ContractAddress', () => { expect(() => { token.transferFrom(Z_OWNER, SOME_CONTRACT, TOKENID_1); }).toThrow('NonFungibleToken: Unsafe Transfer'); }); it('should not transfer to zero address', () => { - token._mint(Z_OWNER, TOKENID_1); expect(() => { token.transferFrom(Z_OWNER, ZERO_KEY, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Receiver'); }); it('should not transfer from zero address', () => { - token._mint(Z_OWNER, TOKENID_1); expect(() => { token.transferFrom(ZERO_KEY, Z_SPENDER, TOKENID_1); }).toThrow('NonFungibleToken: Incorrect Owner'); }); it('should not transfer from unauthorized', () => { - _caller = SPENDER; - token._mint(Z_OWNER, TOKENID_1); + _caller = UNAUTHORIZED; expect(() => { - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + token.transferFrom(Z_OWNER, Z_UNAUTHORIZED, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Insufficient Approval'); }); it('should not transfer token that has not been minted', () => { _caller = OWNER; expect(() => { - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + token.transferFrom(Z_OWNER, Z_SPENDER, NON_EXISTENT_TOKEN, _caller); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should transfer token via approved operator', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.approve(Z_SPENDER, TOKENID_1, OWNER); _caller = SPENDER; @@ -461,7 +458,6 @@ describe('NonFungibleToken', () => { it('should transfer token via approvedForAll operator', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, OWNER); _caller = SPENDER; @@ -471,19 +467,23 @@ describe('NonFungibleToken', () => { it('should allow transfer to same address', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); + token._approve(Z_SPENDER, TOKENID_1, Z_OWNER); + token._setApprovalForAll(Z_OWNER, Z_SPENDER, true); + expect(() => { token.transferFrom(Z_OWNER, Z_OWNER, TOKENID_1, _caller); }).not.toThrow(); expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); + expect(token._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1)).toEqual(true); }); it('should not transfer after approval revocation', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.approve(Z_SPENDER, TOKENID_1, _caller); token.approve(ZERO_KEY, TOKENID_1, _caller); + _caller = SPENDER; expect(() => { token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); @@ -492,9 +492,9 @@ describe('NonFungibleToken', () => { it('should not transfer after approval for all revocation', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, _caller); token.setApprovalForAll(Z_SPENDER, false, _caller); + _caller = SPENDER; expect(() => { token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); @@ -503,9 +503,9 @@ describe('NonFungibleToken', () => { it('should transfer multiple tokens in sequence', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token._mint(Z_OWNER, TOKENID_2); token._mint(Z_OWNER, TOKENID_3); + token.approve(Z_SPENDER, TOKENID_1, _caller); token.approve(Z_SPENDER, TOKENID_2, _caller); token.approve(Z_SPENDER, TOKENID_3, _caller); @@ -533,10 +533,12 @@ describe('NonFungibleToken', () => { it('should revoke approval after transferFrom', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.approve(Z_SPENDER, TOKENID_1, _caller); + token._setApprovalForAll(Z_OWNER, Z_SPENDER, true); + token.transferFrom(Z_OWNER, Z_OTHER, TOKENID_1, _caller); expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); + expect(token._isAuthorized(Z_OTHER, Z_SPENDER, TOKENID_1)).toBe(false); }); }); @@ -699,7 +701,7 @@ describe('NonFungibleToken', () => { it('should throw if auth is unauthorized', () => { token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._approve(Z_SPENDER, TOKENID_1, Z_SPENDER); + token._approve(Z_SPENDER, TOKENID_1, Z_UNAUTHORIZED); }).toThrow('NonFungibleToken: Invalid Approver'); }); @@ -726,28 +728,33 @@ describe('NonFungibleToken', () => { }); describe('_isAuthorized', () => { + beforeEach(() => { + token._mint(Z_OWNER, TOKENID_1); + }); + it('should return true if spender is authorized', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.approve(Z_SPENDER, TOKENID_1, _caller); expect(token._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1)).toBe(true); }); it('should return true if spender is authorized for all', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, _caller); expect(token._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1)).toBe(true); }); it('should return true if spender is owner', () => { - token._mint(Z_OWNER, TOKENID_1); expect(token._isAuthorized(Z_OWNER, Z_OWNER, TOKENID_1)).toBe(true); }); it('should return false if spender is zero address', () => { expect(token._isAuthorized(Z_OWNER, ZERO_KEY, TOKENID_1)).toBe(false); }); + + it('should return false for unauthorized', () => { + expect(token._isAuthorized(Z_OWNER, Z_UNAUTHORIZED, TOKENID_1)).toBe(false); + }); }); describe('_getApproved', () => { @@ -845,8 +852,11 @@ describe('NonFungibleToken', () => { }); describe('_burn', () => { - it('should burn token', () => { + beforeEach(() => { token._mint(Z_OWNER, TOKENID_1); + }); + + it('should burn token', () => { expect(token.balanceOf(Z_OWNER)).toEqual(1n); token._burn(TOKENID_1); @@ -856,13 +866,12 @@ describe('NonFungibleToken', () => { it('should not burn a token that does not exist', () => { expect(() => { - token._burn(TOKENID_1); + token._burn(NON_EXISTENT_TOKEN); }).toThrow('NonFungibleToken: Invalid Sender'); }); it('should clear approval when token is burned', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.approve(Z_SPENDER, TOKENID_1, _caller); expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); @@ -871,9 +880,9 @@ describe('NonFungibleToken', () => { }); it('should burn multiple tokens in sequence', () => { - token._mint(Z_OWNER, TOKENID_1); token._mint(Z_OWNER, TOKENID_2); token._mint(Z_OWNER, TOKENID_3); + token._burn(TOKENID_1); token._burn(TOKENID_2); token._burn(TOKENID_3); @@ -888,7 +897,6 @@ describe('NonFungibleToken', () => { }); it('should burn after transfer', () => { - token._mint(Z_OWNER, TOKENID_1); token._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); token._burn(TOKENID_1); expect(token._ownerOf(TOKENID_1)).toEqual(ZERO_KEY); @@ -896,7 +904,6 @@ describe('NonFungibleToken', () => { it('should burn after approval', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.approve(Z_SPENDER, TOKENID_1, _caller); token._burn(TOKENID_1); expect(token._ownerOf(TOKENID_1)).toEqual(ZERO_KEY); @@ -933,7 +940,7 @@ describe('NonFungibleToken', () => { it('should throw if from does not own token', () => { token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._transfer(Z_SPENDER, Z_SPENDER, TOKENID_1); + token._transfer(Z_UNAUTHORIZED, Z_SPENDER, TOKENID_1); }).toThrow('NonFungibleToken: Incorrect Owner'); }); From c25918fe83050d52bc0494847b6a80af8a2639bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Sat, 14 Jun 2025 22:26:03 -0400 Subject: [PATCH 200/282] fmt file --- contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index 17fb4714..48c3a112 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -753,7 +753,9 @@ describe('NonFungibleToken', () => { }); it('should return false for unauthorized', () => { - expect(token._isAuthorized(Z_OWNER, Z_UNAUTHORIZED, TOKENID_1)).toBe(false); + expect(token._isAuthorized(Z_OWNER, Z_UNAUTHORIZED, TOKENID_1)).toBe( + false, + ); }); }); From 49d0103fb566594760b23985a954452d37111b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:28:44 -0400 Subject: [PATCH 201/282] Reduce duplicate code --- .../nonFungibleToken/src/test/nonFungibleToken.test.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index 48c3a112..460d9882 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -165,6 +165,10 @@ describe('NonFungibleToken', () => { }); describe('tokenURI', () => { + beforeEach(() => { + token._mint(Z_OWNER, TOKENID_1); + }); + it('should throw if token does not exist', () => { expect(() => { token.tokenURI(NON_EXISTENT_TOKEN); @@ -172,33 +176,28 @@ describe('NonFungibleToken', () => { }); it('should return the empty string if tokenURI set as default value', () => { - token._mint(Z_OWNER, TOKENID_1); token._setTokenURI(TOKENID_1, EMPTY_STRING); expect(token.tokenURI(TOKENID_1)).toEqual(EMPTY_STRING); }); it('should return some string if tokenURI is set', () => { - token._mint(Z_OWNER, TOKENID_1); token._setTokenURI(TOKENID_1, SOME_STRING); expect(token.tokenURI(TOKENID_1)).toEqual(SOME_STRING); }); it('should return very long tokenURI', () => { const longURI = 'A'.repeat(1000); - token._mint(Z_OWNER, TOKENID_1); token._setTokenURI(TOKENID_1, longURI); expect(token.tokenURI(TOKENID_1)).toEqual(longURI); }); it('should return tokenURI with special characters', () => { const specialURI = '!@#$%^&*()_+'; - token._mint(Z_OWNER, TOKENID_1); token._setTokenURI(TOKENID_1, specialURI); expect(token.tokenURI(TOKENID_1)).toEqual(specialURI); }); it('should update tokenURI multiple times', () => { - token._mint(Z_OWNER, TOKENID_1); token._setTokenURI(TOKENID_1, 'URI1'); token._setTokenURI(TOKENID_1, 'URI2'); token._setTokenURI(TOKENID_1, 'URI3'); @@ -206,7 +205,6 @@ describe('NonFungibleToken', () => { }); it('should maintain tokenURI after token transfer', () => { - token._mint(Z_OWNER, TOKENID_1); token._setTokenURI(TOKENID_1, SOME_STRING); token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID_1); expect(token.tokenURI(TOKENID_1)).toEqual(SOME_STRING); From bc56a951727762f12b4bc16e26150179f2d09cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Mon, 16 Jun 2025 16:35:41 -0400 Subject: [PATCH 202/282] Update tokenURI behavior, add tests, update mocks, add emptyString() --- .../src/NonFungibleToken.compact | 16 +++++++++++++++- .../src/test/mocks/MockNonFungibleToken.compact | 4 ++++ .../MockUninitializedNonFungibleToken.compact | 6 +++++- .../test/mocks/NonFungibleTokenTesting.compact | 16 +++++++++++++++- .../src/test/nonFungibleToken.test.ts | 10 ++++++++++ .../test/simulators/NonFungibleTokenSimulator.ts | 10 ++++++++++ 6 files changed, 59 insertions(+), 3 deletions(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index 430e424f..02b279c8 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -132,7 +132,8 @@ module NonFungibleToken { } /** - * @description Returns the token URI for the given `tokenId`. + * @description Returns the token URI for the given `tokenId`. Returns the empty + * string if a tokenURI does not exist. * * Requirements: * - The contract must have been initialized. @@ -151,6 +152,10 @@ module NonFungibleToken { Initializable_assertInitialized(); _requireOwned(tokenId); + if (!_tokenURIs.member(tokenId)) { + return emptyString(); + } + return _tokenURIs.lookup(tokenId); } @@ -671,5 +676,14 @@ module NonFungibleToken { return from; } + + /** + * @description A helper function that returns the empty string: "" + + * @return {Opaque<"string">} - The empty string: "" + */ + pure circuit emptyString(): Opaque<"string"> { + return default>; + } } diff --git a/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact index ff75aa7d..c782c1bd 100644 --- a/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact @@ -163,3 +163,7 @@ export circuit _unsafeMint( ): [] { return NonFungibleToken__unsafeMint(to, tokenId); } + +export pure circuit emptyString(): Opaque<"string"> { + return NonFungibleToken_emptyString(); +} \ No newline at end of file diff --git a/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact b/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact index ca24d4e7..4aa48426 100644 --- a/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact @@ -154,5 +154,9 @@ export circuit _unsafeMint( to: Either, tokenId: Uint<128> ): [] { - return NonFungibleToken__unsafeMint(to, tokenId); + return NonFungibleToken__unsafeMint(to, tokenId); } + +export pure circuit emptyString(): Opaque<"string"> { + return NonFungibleToken_emptyString(); +} \ No newline at end of file diff --git a/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact b/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact index fa53308d..c36730f6 100644 --- a/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact +++ b/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact @@ -132,7 +132,8 @@ module NonFungibleTokenTesting { } /** - * @description Returns the token URI for the given `tokenId`. + * @description Returns the token URI for the given `tokenId`. Returns the empty + * string if a tokenURI does not exist. * * Requirements: * - The contract must have been initialized. @@ -151,6 +152,10 @@ module NonFungibleTokenTesting { Initializable_assertInitialized(); _requireOwned(tokenId); + if (!_tokenURIs.member(tokenId)) { + return emptyString(); + } + return _tokenURIs.lookup(tokenId); } @@ -671,4 +676,13 @@ module NonFungibleTokenTesting { return from; } + + /** + * @description A helper function that returns the empty string: "" + + * @return {Opaque<"string">} - The empty string: "" + */ + export pure circuit emptyString(): Opaque<"string"> { + return default>; + } } \ No newline at end of file diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index 460d9882..3fd96c26 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -175,6 +175,10 @@ describe('NonFungibleToken', () => { }).toThrow('NonFungibleToken: Nonexistent Token'); }); + it('should return the empty string for an unset tokenURI', () => { + expect(token.tokenURI(TOKENID_1)).toEqual(EMPTY_STRING); + }); + it('should return the empty string if tokenURI set as default value', () => { token._setTokenURI(TOKENID_1, EMPTY_STRING); expect(token.tokenURI(TOKENID_1)).toEqual(EMPTY_STRING); @@ -1325,4 +1329,10 @@ describe('Uninitialized NonFungibleToken', () => { }).toThrow('Initializable: contract not initialized'); }); }); + + describe('emptyString', () => { + it('should return the empty string', () => { + expect(token.emptyString()).toBe(''); + }); + }); }); diff --git a/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts b/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts index e0b730a7..c654eb92 100644 --- a/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts +++ b/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts @@ -14,6 +14,7 @@ import { Contract as MockNonFungibleToken, type ZswapCoinPublicKey, ledger, + pureCircuits, } from '../../artifacts/MockNonFungibleToken/contract/index.cjs'; // Combined imports import { type NonFungibleTokenPrivateState, @@ -636,4 +637,13 @@ export class NonFungibleTokenSimulator tokenId, ).context; } + + /** + * @description A helper function that returns the empty string: "" + + * @return {Opaque<"string">} - The empty string: "" + */ + public emptyString(): '' { + return pureCircuits.emptyString() as ''; + } } From aa2ff34613ec24990359222afaa81f552b4927a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Mon, 16 Jun 2025 16:41:16 -0400 Subject: [PATCH 203/282] Move test to correct test block, remove code that doesn't need testing --- .../mocks/MockUninitializedNonFungibleToken.compact | 4 ---- .../src/test/nonFungibleToken.test.ts | 12 ++++++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact b/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact index 4aa48426..1c081109 100644 --- a/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact @@ -155,8 +155,4 @@ export circuit _unsafeMint( tokenId: Uint<128> ): [] { return NonFungibleToken__unsafeMint(to, tokenId); -} - -export pure circuit emptyString(): Opaque<"string"> { - return NonFungibleToken_emptyString(); } \ No newline at end of file diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index 3fd96c26..8bc689c5 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -1121,6 +1121,12 @@ describe('NonFungibleToken', () => { expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); }); + + describe('emptyString', () => { + it('should return the empty string', () => { + expect(token.emptyString()).toBe(''); + }); + }); }); let uninitializedToken: UninitializedNonFungibleTokenSimulator; @@ -1329,10 +1335,4 @@ describe('Uninitialized NonFungibleToken', () => { }).toThrow('Initializable: contract not initialized'); }); }); - - describe('emptyString', () => { - it('should return the empty string', () => { - expect(token.emptyString()).toBe(''); - }); - }); }); From fcb182baa308b568d6ab694b021071bb81e13572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Mon, 16 Jun 2025 16:52:43 -0400 Subject: [PATCH 204/282] fmt file --- contracts/nonFungibleToken/src/NonFungibleToken.compact | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index 02b279c8..8d6ba408 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -685,5 +685,4 @@ module NonFungibleToken { pure circuit emptyString(): Opaque<"string"> { return default>; } -} - +} \ No newline at end of file From e24419b4fead416ef01a4c90e07ca09fb824e3a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Mon, 16 Jun 2025 16:53:44 -0400 Subject: [PATCH 205/282] Add additional behavior checks for 'should revoke approval after transferFrom' --- .../nonFungibleToken/src/test/nonFungibleToken.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index 8bc689c5..d99d79bd 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -541,6 +541,14 @@ describe('NonFungibleToken', () => { token.transferFrom(Z_OWNER, Z_OTHER, TOKENID_1, _caller); expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); expect(token._isAuthorized(Z_OTHER, Z_SPENDER, TOKENID_1)).toBe(false); + + _caller = SPENDER; + expect(() => { + token.approve(Z_UNAUTHORIZED, TOKENID_1, _caller) + }).toThrow('NonFungibleToken: Invalid Approver'); + expect(() => { + token.transferFrom(Z_OTHER, Z_UNAUTHORIZED, TOKENID_1, _caller) + }).toThrow('NonFungibleToken: Insufficient Approval'); }); }); From 0cd917b0c163c2a011c648f6bc64e6f80e2c15ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 19:11:52 -0400 Subject: [PATCH 206/282] Remove redundant assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Fleming Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- contracts/nonFungibleToken/src/NonFungibleToken.compact | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index 8d6ba408..e4e1e6dc 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -66,7 +66,6 @@ module NonFungibleToken { name_: Opaque<"string">, symbol_: Opaque<"string"> ): [] { - Initializable_assertNotInitialized(); Initializable_initialize(); _name = name_; _symbol = symbol_; From 02a4768112320d55a8ea150769a09e43df0c69ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 19:14:46 -0400 Subject: [PATCH 207/282] fmt NonFungibleToken.compact MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Fleming Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- contracts/nonFungibleToken/src/NonFungibleToken.compact | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index e4e1e6dc..d7408885 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -369,7 +369,7 @@ module NonFungibleToken { return _tokenApprovals.lookup(tokenId); } - /** + /** * @description Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in * particular (ignoring whether it is owned by `owner`). * @@ -551,7 +551,7 @@ module NonFungibleToken { } /** - * @description Approve `to` to operate on `tokenId` + * @description Approve `to` to operate on `tokenId` * * Requirements: * - The contract must have been initialized. From b7dc8650f2a63653d515ba759a76957d8cb54691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 19:16:49 -0400 Subject: [PATCH 208/282] Improve test readability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Fleming Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index d99d79bd..0c770326 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -304,7 +304,8 @@ describe('NonFungibleToken', () => { }); it('should get current approved spender', () => { - token.approve(Z_OWNER, TOKENID_1); + _caller = OWNER; + token.approve(Z_OWNER, TOKENID_1, _caller); expect(token.getApproved(TOKENID_1)).toEqual(Z_OWNER); }); From d0d11f3694f8ab9d93f0fbef999c86a413810092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 19:18:00 -0400 Subject: [PATCH 209/282] Improve Test Readability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Fleming Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index 0c770326..e24ced65 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -332,10 +332,10 @@ describe('NonFungibleToken', () => { }); it('should allow operator to manage owner tokens', () => { - _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); token._mint(Z_OWNER, TOKENID_2); token._mint(Z_OWNER, TOKENID_3); + _caller = OWNER; token.setApprovalForAll(Z_SPENDER, true, _caller); _caller = SPENDER; From 84076ae8a57a02381b53bacd28a619692e1b6736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:21:55 -0400 Subject: [PATCH 210/282] test(nonfungibletoken): Add transfer token without approvers or operators test --- .../nonFungibleToken/src/test/nonFungibleToken.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index e24ced65..2e613be6 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -450,6 +450,12 @@ describe('NonFungibleToken', () => { }).toThrow('NonFungibleToken: Nonexistent Token'); }); + it('should transfer token without approvers or operators', () => { + _caller = OWNER; + token.transferFrom(Z_OWNER, Z_RECIPIENT, TOKENID_1, _caller); + expect(token.ownerOf(TOKENID_1)).toBe(Z_RECIPIENT); + }) + it('should transfer token via approved operator', () => { _caller = OWNER; token.approve(Z_SPENDER, TOKENID_1, OWNER); From 2c3384acd3f46c9deadfcd6b851fb9b95749457e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:30:58 -0400 Subject: [PATCH 211/282] test(nonfungibletoken): Fix broken test --- contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index 2e613be6..c67d1b20 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -453,7 +453,7 @@ describe('NonFungibleToken', () => { it('should transfer token without approvers or operators', () => { _caller = OWNER; token.transferFrom(Z_OWNER, Z_RECIPIENT, TOKENID_1, _caller); - expect(token.ownerOf(TOKENID_1)).toBe(Z_RECIPIENT); + expect(token.ownerOf(TOKENID_1)).toEqual(Z_RECIPIENT); }) it('should transfer token via approved operator', () => { From 9d0d82644a791dc3893e99e4c5473289bf4126f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:31:20 -0400 Subject: [PATCH 212/282] test(nonfungibletoken): Add additional expectation to test --- contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index c67d1b20..7bb4e8d4 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -596,6 +596,7 @@ describe('NonFungibleToken', () => { _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); token.approve(Z_OTHER, TOKENID_1, _caller); + expect(token.getApproved(TOKENID_1)).toEqual(Z_OTHER); const prevOwner = token._update(Z_SPENDER, TOKENID_1, ZERO_KEY); expect(prevOwner).toEqual(Z_OWNER); From 6a7e037627dedcdeee423fea8fe1302f835bf169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:39:21 -0400 Subject: [PATCH 213/282] tests(nonfungibletoken): Add happy path tests for _checkAuthorized --- .../src/test/nonFungibleToken.test.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index 7bb4e8d4..85b95994 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -737,12 +737,26 @@ describe('NonFungibleToken', () => { }).toThrow('NonFungibleToken: Nonexistent Token'); }); - it('should throw if spender does not have approval', () => { + it('should throw if unauthorized', () => { token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._checkAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1); + token._checkAuthorized(Z_OWNER, Z_UNAUTHORIZED, TOKENID_1); }).toThrow('NonFungibleToken: Insufficient Approval'); }); + + it('should not throw if approved', () => { + token._mint(Z_OWNER, TOKENID_1); + _caller = OWNER; + token.approve(Z_SPENDER, TOKENID_1, _caller); + token._checkAuthorized(Z_OWNER ,Z_SPENDER, TOKENID_1); + }); + + it('should not throw if approvedForAll', () => { + token._mint(Z_OWNER, TOKENID_1); + _caller = OWNER; + token.setApprovalForAll(Z_SPENDER, true, _caller); + token._checkAuthorized(Z_OWNER ,Z_SPENDER, TOKENID_1); + }); }); describe('_isAuthorized', () => { From d4c98fcc18de9eeefd935e3435ffffbbe5555a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:44:14 -0400 Subject: [PATCH 214/282] tests(nonfungibletoken): Add test for _getApproved --- .../src/test/nonFungibleToken.test.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index 85b95994..5afafce5 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -792,16 +792,23 @@ describe('NonFungibleToken', () => { }); describe('_getApproved', () => { + beforeEach(() => { + token._mint(Z_OWNER, TOKENID_1); + }); + it('should return zero address if token is not minted', () => { - expect(token._getApproved(TOKENID_1)).toEqual(ZERO_KEY); + expect(token._getApproved(NON_EXISTENT_TOKEN)).toEqual(ZERO_KEY); }); it('should return approved address', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.approve(Z_SPENDER, TOKENID_1, _caller); expect(token._getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); + + it('should return zero address if no approvals', () => { + expect(token._getApproved(TOKENID_1)).toEqual(ZERO_KEY); + }); }); describe('_setApprovalForAll', () => { From 5e631892b241e6eca52e806f0c2f918cb932c562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:49:24 -0400 Subject: [PATCH 215/282] tests(nonfungibletoken): Add assertion to _unsafeMint --- contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index 5afafce5..a088f43a 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -3,6 +3,7 @@ import { beforeEach, describe, expect, it } from 'vitest'; import { NonFungibleTokenSimulator } from './simulators/NonFungibleTokenSimulator.js'; import { UninitializedNonFungibleTokenSimulator } from './simulators/UninitializedNonFungibleTokenSimulator.js'; import { + ZERO_ADDRESS, ZERO_KEY, createEitherTestContractAddress, createEitherTestUser, @@ -1025,6 +1026,10 @@ describe('NonFungibleToken', () => { expect(() => { token._unsafeMint(ZERO_KEY, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Receiver'); + + expect(() => { + token._unsafeMint(ZERO_ADDRESS, TOKENID_1); + }).toThrow('NonFungibleToken: Invalid Receiver'); }); it('should not mint a token that already exists', () => { From 6c9faa2512ae8c212b10f9038ef919de196f5d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 22:01:23 -0400 Subject: [PATCH 216/282] tests(nonfungibletoken): Reduce boilerplate code, improve readability, add assertion for ZERO_ADDRESS --- .../src/test/nonFungibleToken.test.ts | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index a088f43a..8c84202b 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -1051,15 +1051,17 @@ describe('NonFungibleToken', () => { }); describe('_unsafeTransfer', () => { - it('should transfer to ContractAddress', () => { + beforeEach(() => { token._mint(Z_OWNER, TOKENID_1); + }); + + it('should transfer to ContractAddress', () => { expect(() => { token._unsafeTransfer(Z_OWNER, SOME_CONTRACT, TOKENID_1); }).not.toThrow(); }); it('should transfer token to public key', () => { - token._mint(Z_OWNER, TOKENID_1); expect(token.balanceOf(Z_OWNER)).toEqual(1n); expect(token.balanceOf(Z_SPENDER)).toEqual(0n); expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); @@ -1074,12 +1076,15 @@ describe('NonFungibleToken', () => { expect(() => { token._unsafeTransfer(Z_OWNER, ZERO_KEY, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Receiver'); + + expect(() => { + token._unsafeTransfer(Z_OWNER, ZERO_ADDRESS, TOKENID_1); + }).toThrow('NonFungibleToken: Invalid Receiver'); }); it('should throw if from does not own token', () => { - token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._unsafeTransfer(Z_SPENDER, Z_SPENDER, TOKENID_1); + token._unsafeTransfer(Z_UNAUTHORIZED, Z_UNAUTHORIZED, TOKENID_1); }).toThrow('NonFungibleToken: Incorrect Owner'); }); @@ -1091,7 +1096,6 @@ describe('NonFungibleToken', () => { it('should revoke approval after _unsafeTransfer', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.approve(Z_SPENDER, TOKENID_1, _caller); token._unsafeTransfer(Z_OWNER, Z_OTHER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); @@ -1099,45 +1103,52 @@ describe('NonFungibleToken', () => { }); describe('_unsafeTransferFrom', () => { - it('should transfer to ContractAddress', () => { + beforeEach(() => { token._mint(Z_OWNER, TOKENID_1); + }); + + it('should transfer to ContractAddress', () => { expect(() => { token._unsafeTransferFrom(Z_OWNER, SOME_CONTRACT, TOKENID_1); }).not.toThrow(); }); it('should not transfer to zero address', () => { - token._mint(Z_OWNER, TOKENID_1); expect(() => { token._unsafeTransferFrom(Z_OWNER, ZERO_KEY, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Receiver'); + + expect(() => { + token._unsafeTransferFrom(Z_OWNER, ZERO_ADDRESS, TOKENID_1); + }).toThrow('NonFungibleToken: Invalid Receiver'); }); it('should not transfer from zero address', () => { - token._mint(Z_OWNER, TOKENID_1); expect(() => { token._unsafeTransferFrom(ZERO_KEY, Z_SPENDER, TOKENID_1); }).toThrow('NonFungibleToken: Incorrect Owner'); + + expect(() => { + token._unsafeTransferFrom(ZERO_ADDRESS, Z_SPENDER, TOKENID_1); + }).toThrow('NonFungibleToken: Incorrect Owner'); }); it('unapproved operator should not transfer', () => { _caller = SPENDER; - token._mint(Z_OWNER, TOKENID_1); expect(() => { - token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + token._unsafeTransferFrom(Z_OWNER, Z_UNAUTHORIZED, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Insufficient Approval'); }); it('should not transfer token that has not been minted', () => { _caller = OWNER; expect(() => { - token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, NON_EXISTENT_TOKEN, _caller); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should transfer token via approved operator', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.approve(Z_SPENDER, TOKENID_1, OWNER); _caller = SPENDER; @@ -1147,7 +1158,6 @@ describe('NonFungibleToken', () => { it('should transfer token via approvedForAll operator', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.setApprovalForAll(Z_SPENDER, true, OWNER); _caller = SPENDER; @@ -1157,7 +1167,6 @@ describe('NonFungibleToken', () => { it('should revoke approval after _unsafeTransferFrom', () => { _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); token.approve(Z_SPENDER, TOKENID_1, _caller); token._unsafeTransferFrom(Z_OWNER, Z_OTHER, TOKENID_1, _caller); expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); From 36526514508ce354da83d678f12eb7ccff7c205f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 22:17:11 -0400 Subject: [PATCH 217/282] tests(nonfungibletoken): Add tests to _unsafeTransferFrom --- .../src/test/nonFungibleToken.test.ts | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index 8c84202b..b06aa515 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -1147,7 +1147,7 @@ describe('NonFungibleToken', () => { }).toThrow('NonFungibleToken: Nonexistent Token'); }); - it('should transfer token via approved operator', () => { + it('should transfer token to spender via approved operator', () => { _caller = OWNER; token.approve(Z_SPENDER, TOKENID_1, OWNER); @@ -1156,7 +1156,16 @@ describe('NonFungibleToken', () => { expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); - it('should transfer token via approvedForAll operator', () => { + it('should transfer token to ContractAddress via approved operator', () => { + _caller = OWNER; + token.approve(Z_SPENDER, TOKENID_1, OWNER); + + _caller = SPENDER; + token._unsafeTransferFrom(Z_OWNER, SOME_CONTRACT, TOKENID_1, _caller); + expect(token.ownerOf(TOKENID_1)).toEqual(SOME_CONTRACT); + }); + + it('should transfer token to spender via approvedForAll operator', () => { _caller = OWNER; token.setApprovalForAll(Z_SPENDER, true, OWNER); @@ -1165,6 +1174,15 @@ describe('NonFungibleToken', () => { expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); + it('should transfer token to ContractAddress via approvedForAll operator', () => { + _caller = OWNER; + token.setApprovalForAll(Z_SPENDER, true, OWNER); + + _caller = SPENDER; + token._unsafeTransferFrom(Z_OWNER, SOME_CONTRACT, TOKENID_1, _caller); + expect(token.ownerOf(TOKENID_1)).toEqual(SOME_CONTRACT); + }); + it('should revoke approval after _unsafeTransferFrom', () => { _caller = OWNER; token.approve(Z_SPENDER, TOKENID_1, _caller); From 3df252a56adbfbb4549a7614ec6016c6d723b275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 22:47:28 -0400 Subject: [PATCH 218/282] tests(nonfungibletoken): Refactor Uninitialized tests --- .../src/test/nonFungibleToken.test.ts | 254 ++++-------------- 1 file changed, 49 insertions(+), 205 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index b06aa515..a00c5cec 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -455,7 +455,7 @@ describe('NonFungibleToken', () => { _caller = OWNER; token.transferFrom(Z_OWNER, Z_RECIPIENT, TOKENID_1, _caller); expect(token.ownerOf(TOKENID_1)).toEqual(Z_RECIPIENT); - }) + }); it('should transfer token via approved operator', () => { _caller = OWNER; @@ -552,10 +552,10 @@ describe('NonFungibleToken', () => { _caller = SPENDER; expect(() => { - token.approve(Z_UNAUTHORIZED, TOKENID_1, _caller) + token.approve(Z_UNAUTHORIZED, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Invalid Approver'); expect(() => { - token.transferFrom(Z_OTHER, Z_UNAUTHORIZED, TOKENID_1, _caller) + token.transferFrom(Z_OTHER, Z_UNAUTHORIZED, TOKENID_1, _caller); }).toThrow('NonFungibleToken: Insufficient Approval'); }); }); @@ -749,14 +749,14 @@ describe('NonFungibleToken', () => { token._mint(Z_OWNER, TOKENID_1); _caller = OWNER; token.approve(Z_SPENDER, TOKENID_1, _caller); - token._checkAuthorized(Z_OWNER ,Z_SPENDER, TOKENID_1); + token._checkAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1); }); it('should not throw if approvedForAll', () => { token._mint(Z_OWNER, TOKENID_1); _caller = OWNER; token.setApprovalForAll(Z_SPENDER, true, _caller); - token._checkAuthorized(Z_OWNER ,Z_SPENDER, TOKENID_1); + token._checkAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1); }); }); @@ -1143,7 +1143,12 @@ describe('NonFungibleToken', () => { it('should not transfer token that has not been minted', () => { _caller = OWNER; expect(() => { - token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, NON_EXISTENT_TOKEN, _caller); + token._unsafeTransferFrom( + Z_OWNER, + Z_SPENDER, + NON_EXISTENT_TOKEN, + _caller, + ); }).toThrow('NonFungibleToken: Nonexistent Token'); }); @@ -1198,6 +1203,39 @@ describe('NonFungibleToken', () => { }); }); +type FailingCircuits = [ + method: keyof UninitializedNonFungibleTokenSimulator, + args: unknown[], +]; // Circuit calls should fail before the args are used + +const circuitsToFail: FailingCircuits[] = [ + ['name', []], + ['symbol', []], + ['balanceOf', [Z_OWNER]], + ['ownerOf', [TOKENID_1]], + ['tokenURI', [TOKENID_1]], + ['approve', [Z_OWNER, TOKENID_1]], + ['getApproved', [TOKENID_1]], + ['setApprovalForAll', [Z_SPENDER, true]], + ['isApprovedForAll', [Z_OWNER, Z_SPENDER]], + ['transferFrom', [Z_OWNER, Z_RECIPIENT, TOKENID_1]], + ['_requireOwned', [TOKENID_1]], + ['_ownerOf', [TOKENID_1]], + ['_update', [Z_SPENDER, TOKENID_1, Z_OWNER]], + ['_approve', [Z_OWNER, TOKENID_1, Z_SPENDER]], + ['_checkAuthorized', [Z_OWNER, Z_SPENDER, TOKENID_1]], + ['_isAuthorized', [Z_OWNER, Z_SPENDER, TOKENID_1]], + ['_getApproved', [TOKENID_1]], + ['_setApprovalForAll', [Z_OWNER, Z_SPENDER, true]], + ['_mint', [Z_OWNER, TOKENID_1]], + ['_burn', [TOKENID_1]], + ['_transfer', [Z_OWNER, Z_RECIPIENT, TOKENID_1]], + ['_setTokenURI', [TOKENID_1]], + ['_unsafeTransferFrom', [Z_OWNER, Z_RECIPIENT, TOKENID_1]], + ['_unsafeTransfer', [Z_OWNER, Z_RECIPIENT, TOKENID_1]], + ['_unsafeMint', [Z_OWNER, TOKENID_1]], +]; + let uninitializedToken: UninitializedNonFungibleTokenSimulator; describe('Uninitialized NonFungibleToken', () => { @@ -1205,203 +1243,9 @@ describe('Uninitialized NonFungibleToken', () => { uninitializedToken = new UninitializedNonFungibleTokenSimulator(); }); - describe('name', () => { - it('should throw', () => { - expect(() => { - uninitializedToken.name(); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('symbol', () => { - it('should throw', () => { - expect(() => { - uninitializedToken.symbol(); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('balanceOf', () => { - it('should throw', () => { - expect(() => { - uninitializedToken.balanceOf(Z_OWNER); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('ownerOf', () => { - it('should throw', () => { - expect(() => { - uninitializedToken.ownerOf(TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('tokenURI', () => { - it('should throw', () => { - expect(() => { - uninitializedToken.tokenURI(TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('approve', () => { - it('should throw', () => { - expect(() => { - uninitializedToken.approve(Z_OWNER, TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('getApproved', () => { - it('should throw', () => { - expect(() => { - uninitializedToken.getApproved(TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('setApprovalForAll', () => { - it('should throw', () => { - expect(() => { - uninitializedToken.setApprovalForAll(Z_OWNER, true); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('isApprovedForAll', () => { - it('should throw', () => { - expect(() => { - uninitializedToken.isApprovedForAll(Z_OWNER, Z_SPENDER); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('transferFrom', () => { - it('should throw', () => { - expect(() => { - uninitializedToken.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_requireOwned', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._requireOwned(TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_ownerOf', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._ownerOf(TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_update', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._update(Z_OWNER, TOKENID_1, Z_SPENDER); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_approve', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._approve(Z_OWNER, TOKENID_1, Z_SPENDER); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_checkAuthorized', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._checkAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_isAuthorized', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_getApproved', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._getApproved(TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_setApprovalForAll', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._setApprovalForAll(Z_OWNER, Z_SPENDER, true); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_mint', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._mint(Z_OWNER, TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_burn', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._burn(TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_transfer', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_setTokenURI', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._setTokenURI(TOKENID_1, SOME_STRING); - }).toThrow('Initializable: contract not initialized'); - }); + it.each(circuitsToFail)('%s should fail', (circuitName, args) => { + expect(() => { + (uninitializedToken[circuitName] as (...args: unknown[]) => unknown)(...args); + }).toThrow('Initializable: contract not initialized'); }); - - describe('_unsafeTransferFrom', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_unsafeTransfer', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._unsafeTransfer(Z_OWNER, Z_SPENDER, TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); - - describe('_unsafeMint', () => { - it('should throw', () => { - expect(() => { - uninitializedToken._unsafeMint(Z_OWNER, TOKENID_1); - }).toThrow('Initializable: contract not initialized'); - }); - }); -}); +}); \ No newline at end of file From ebc3c4ffc3b8b2ec6ba552bda41bea7bcb0a3225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 22:48:37 -0400 Subject: [PATCH 219/282] fmt file --- .../nonFungibleToken/src/test/nonFungibleToken.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index a00c5cec..a2a03bcb 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -1245,7 +1245,9 @@ describe('Uninitialized NonFungibleToken', () => { it.each(circuitsToFail)('%s should fail', (circuitName, args) => { expect(() => { - (uninitializedToken[circuitName] as (...args: unknown[]) => unknown)(...args); + (uninitializedToken[circuitName] as (...args: unknown[]) => unknown)( + ...args, + ); }).toThrow('Initializable: contract not initialized'); }); -}); \ No newline at end of file +}); From 3092d21b7305a6c03bbcbc2eda606ce1c4164bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 22:54:09 -0400 Subject: [PATCH 220/282] tests(utils): Add stricter equality checks --- contracts/utils/src/test/utils.test.ts | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 8feca5d1..532da32e 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -36,23 +36,29 @@ describe('Utils', () => { describe('isKeyOrAddressEqual', () => { it('should return true for two matching pubkeys', () => { - expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_SOME_KEY)).toBeTruthy(); + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_SOME_KEY)).toBe(true); }); it('should return true for two matching contract addresses', () => { - expect( - contract.isKeyOrAddressEqual(SOME_CONTRACT, SOME_CONTRACT), - ).toBeTruthy(); + expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, SOME_CONTRACT)).toBe( + true, + ); }); it('should return false for two different pubkeys', () => { - expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_OTHER_KEY)).toBeFalsy(); + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_OTHER_KEY)).toBe(false); }); it('should return false for two different contract addresses', () => { - expect( - contract.isKeyOrAddressEqual(SOME_CONTRACT, OTHER_CONTRACT), - ).toBeFalsy(); + expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, OTHER_CONTRACT)).toBe( + false, + ); + }); + + it('should return false for two different address types', () => { + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, SOME_CONTRACT)).toBe( + false, + ); }); it('should return false for two different address types of equal value', () => { @@ -61,7 +67,7 @@ describe('Utils', () => { contractUtils.ZERO_KEY, contractUtils.ZERO_ADDRESS, ), - ).toBeFalsy(); + ).toBe(false); }); }); From 82db2a04650434920435d7f6b66acf3c05ead8ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Tue, 17 Jun 2025 23:55:07 -0400 Subject: [PATCH 221/282] Update method docs with @circuitInfo --- .../src/NonFungibleToken.compact | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index d7408885..cf6790ed 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -74,6 +74,8 @@ module NonFungibleToken { /** * @description Returns the number of tokens in `owner`'s account. * + * @circuitInfo k=10, rows=309 + * * Requirements: * - The contract must have been initialized. * @@ -92,6 +94,8 @@ module NonFungibleToken { /** * @description Returns the owner of the `tokenId` token. * + * @circuitInfo k=10, rows=320 + * * Requirements: * - The contract must have been initialized. * - The `tokenId` must exist. @@ -107,6 +111,8 @@ module NonFungibleToken { /** * @description Returns the token name. * + * @circuitInfo k=10, rows=36 + * * Requirements: * - The contract must have been initialized. * @@ -120,6 +126,8 @@ module NonFungibleToken { /** * @description Returns the symbol of the token. * + * @circuitInfo k=10, rows=36 + * * Requirements: * - The contract must have been initialized. * @@ -134,6 +142,8 @@ module NonFungibleToken { * @description Returns the token URI for the given `tokenId`. Returns the empty * string if a tokenURI does not exist. * + * @circuitInfo k=10, rows=326 + * * Requirements: * - The contract must have been initialized. * - The `tokenId` must exist. @@ -161,6 +171,8 @@ module NonFungibleToken { /** * @description Sets the the URI as `tokenURI` for the given `tokenId`. * + * @circuitInfo k=10, rows=283 + * * Requirements: * - The contract must have been initialized. * - The `tokenId` must exist. @@ -184,6 +196,8 @@ module NonFungibleToken { * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * + * @circuitInfo k=10, rows=993 + * * Requirements: * - The contract must have been initialized. * - The caller must either own the token or be an approved operator. @@ -209,6 +223,8 @@ module NonFungibleToken { /** * @description Returns the account approved for `tokenId` token. * + * @circuitInfo k=10, rows=439 + * * Requirements: * - The contract must have been initialized. * - `tokenId` must exist. @@ -227,6 +243,8 @@ module NonFungibleToken { * @description Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} for any token owned by the caller. * + * @circuitInfo k=10, rows=439 + * * Requirements: * - The contract must have been initialized. * - The `operator` cannot be the address zero. @@ -251,6 +269,8 @@ module NonFungibleToken { /** * @description Returns if the `operator` is allowed to manage all of the assets of `owner`. * + * @circuitInfo k=10, rows=621 + * * Requirements: * - The contract must have been initialized. * @@ -273,6 +293,8 @@ module NonFungibleToken { /** * @description Transfers `tokenId` token from `from` to `to`. * + * @circuitInfo k=11, rows=2023 + * * Requirements: * - The contract must have been initialized. * - `from` cannot be the zero address. @@ -300,6 +322,8 @@ module NonFungibleToken { /** * @description Transfers `tokenId` token from `from` to `to`. It does NOT check if the recipient is a ContractAddress. * + * @circuitInfo k=11, rows=2020 + * * Requirements: * - The contract must have been initialized. * - `from` cannot be the zero address. @@ -337,6 +361,8 @@ module NonFungibleToken { /** * @description Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist * + * @circuitInfo k=10, rows=253 + * * Requirements: * - The contract must have been initialized. * @@ -355,6 +381,8 @@ module NonFungibleToken { /** * @description Returns the approved address for `tokenId`. Returns the zero address if `tokenId` is not minted. * + * @circuitInfo k=10, rows=253 + * * Requirements: * - The contract must have been initialized. * @@ -373,6 +401,8 @@ module NonFungibleToken { * @description Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in * particular (ignoring whether it is owned by `owner`). * + * @circuitInfo k=11, rows=1128 + * * Requirements: * - The contract must have been initialized. * @@ -399,6 +429,8 @@ module NonFungibleToken { /** * @description Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. * + * @circuitInfo k=11, rows=1181 + * * Requirements: * - The contract must have been initialized. * - `spender` has approval from `owner` for `tokenId` OR `spender` has approval to manage all of `owner`'s assets. @@ -426,6 +458,8 @@ module NonFungibleToken { /** * @description Mints `tokenId` and transfers it to `to`. * + * @circuitInfo k=11, rows=1073 + * * Requirements: * - The contract must have been initialized. * - `tokenId` must not exist. @@ -449,6 +483,8 @@ module NonFungibleToken { /** * @description Mints `tokenId` and transfers it to `to`. It does NOT check if the recipient is a ContractAddress. * + * @circuitInfo k=11, rows=1070 + * * Requirements: * - The contract must have been initialized. * - `tokenId` must not exist. @@ -478,6 +514,8 @@ module NonFungibleToken { * The approval is cleared when the token is burned. * This circuit does not check if the sender is authorized to operate on the token. * + * @circuitInfo k=10, rows=509 + * * Requirements: * - The contract must have been initialized. * - `tokenId` must exist. @@ -495,6 +533,8 @@ module NonFungibleToken { * @description Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on own_public_key(). * + * @circuitInfo k=11, rows=1284 + * * Requirements: * - The contract must have been initialized. * - `to` cannot be the zero address. @@ -522,6 +562,8 @@ module NonFungibleToken { * As opposed to {_unsafeTransferFrom}, this imposes no restrictions on own_public_key(). * It does NOT check if the recipient is a ContractAddress. * + * @circuitInfo k=11, rows=1281 + * * Requirements: * - The contract must have been initialized. * - `to` cannot be the zero address. @@ -553,6 +595,8 @@ module NonFungibleToken { /** * @description Approve `to` to operate on `tokenId` * + * @circuitInfo k=11, rows=1169 + * * Requirements: * - The contract must have been initialized. * - If `auth` is non 0, then this function will check that `auth` is either the owner of the token, @@ -582,6 +626,8 @@ module NonFungibleToken { /** * @description Approve `operator` to operate on all of `owner` tokens * + * @circuitInfo k=10, rows=554 + * * Requirements: * - The contract must have been initialized. * - `operator` can't be the address zero. @@ -613,6 +659,8 @@ module NonFungibleToken { * @description Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). * Returns the owner. * + * @circuitInfo k=10, rows=318 + * * Requirements: * - The contract must have been initialized. * - `tokenId` must exist. @@ -632,6 +680,8 @@ module NonFungibleToken { * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. * + * @circuitInfo k=12, rows=2049 + * * Requirements: * - The contract must have been initialized. * - If `auth` is non 0, then this function will check that `auth` is either the owner of the token, @@ -678,7 +728,7 @@ module NonFungibleToken { /** * @description A helper function that returns the empty string: "" - + * * @return {Opaque<"string">} - The empty string: "" */ pure circuit emptyString(): Opaque<"string"> { From 7770d1b671dd10639c2d990e6c680c2f4d3659d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:17:31 -0400 Subject: [PATCH 222/282] Add legal language to security policy (#105) --- SECURITY.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SECURITY.md b/SECURITY.md index 8b23055a..68902d38 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,3 +1,7 @@ # Security Security vulnerabilities should be disclosed to the project maintainers by email to . + +## Legal + +Blockchain is a nascent technology and carries a high level of risk and uncertainty. OpenZeppelin makes certain software available under open source licenses, which disclaim all warranties in relation to the project and which limits the liability of OpenZeppelin. Subject to any particular licensing terms, your use of the project is governed by the terms found at [www.openzeppelin.com/tos](https://www.openzeppelin.com/tos) (the "Terms"). As set out in the Terms, you are solely responsible for any use of the project and you assume all risks associated with any such use. This Security Policy in no way evidences or represents an ongoing duty by any contributor, including OpenZeppelin, to correct any issues or vulnerabilities or alert you to all or any of the risks of utilizing the project. \ No newline at end of file From 93ef757a30ee61c493307dbb482f9d6a66cc5898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 01:09:45 -0400 Subject: [PATCH 223/282] Adds CI Tests, Lints, Compile, Build (#113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> Co-authored-by: Andrew Fleming --- .github/actions/setup/action.yml | 2 + .github/workflows/checks.yml | 8 +-- .github/workflows/codeql.yml | 8 --- .github/workflows/test.yml | 84 ++++++++++++++++++++++++++++++++ README.md | 22 +++++++-- compact/package.json | 2 +- contracts/utils/package.json | 4 +- package.json | 1 - turbo.json | 3 ++ yarn.lock | 39 +++++---------- 10 files changed, 124 insertions(+), 49 deletions(-) create mode 100644 .github/workflows/test.yml diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index bc1d64a1..9cdc577c 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -16,6 +16,7 @@ runs: key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-yarn- + - name: Cache turbo build setup uses: actions/cache@v4 with: @@ -23,6 +24,7 @@ runs: key: ${{ runner.os }}-turbo-${{ hashFiles('.turbo/*') }}-${{ github.sha }} restore-keys: | ${{ runner.os }}-turbo-${{ hashFiles('.turbo/*') }} + - name: Setup Node.js uses: actions/setup-node@v4 with: diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 005fc33e..0e8576e8 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -4,10 +4,10 @@ env: TURBO_TELEMETRY_DISABLED: 1 on: + pull_request: push: - paths: - - '**.ts' - - '**.json' + branches: + - main jobs: checks: @@ -24,4 +24,4 @@ jobs: uses: ./.github/actions/setup - name: Format & Lint - run: turbo fmt-and-lint:ci \ No newline at end of file + run: turbo fmt-and-lint:ci diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a8a8d4b3..ed52739b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -30,8 +30,6 @@ jobs: - name: Setup Environment uses: ./.github/actions/setup - with: - skip-compile: 'true' - name: Initialize CodeQL uses: github/codeql-action/init@v3 @@ -44,9 +42,3 @@ jobs: uses: github/codeql-action/analyze@v3 with: category: "/language:${{ matrix.language }}" - - - name: Cleanup on failure - if: failure() - run: | - echo "Analysis failed. Cleaning up..." - rm -rf contracts/*/src/artifacts/ \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..d8f64297 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,84 @@ +name: Compact Contracts Test Suite + +on: + pull_request: + push: + branches: + - main + +env: + TURBO_TELEMETRY_DISABLED: 1 + COMPILER_VERSION: "0.23.0" + LANGUAGE_VERSION: "0.15.0" + +jobs: + run-suite: + name: Run Test Suite + runs-on: ubuntu-24.04 + timeout-minutes: 15 + + steps: + - name: Check out code + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Recommended by turbo team + + - name: Setup Environment + uses: ./.github/actions/setup + + - name: Install Compact compiler + id: setup + shell: bash + run: | + set -euo pipefail + # Create directory for compiler + COMPACT_HOME="$HOME/compactc" + mkdir -p "$COMPACT_HOME" + + # Create URL + ZIP_FILE="compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip" + DOWNLOAD_URL="https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/${ZIP_FILE}" + + echo "⬇️ Downloading Compact compiler..." + curl -Ls "$DOWNLOAD_URL" -o "$COMPACT_HOME/compactc.zip" + + echo "📦 Extracting..." + unzip -q "$COMPACT_HOME/compactc.zip" -d "$COMPACT_HOME" + chmod +x "$COMPACT_HOME"/{compactc,compactc.bin,zkir} + + echo "📁 Setting environment variables..." + echo "COMPACT_HOME=$COMPACT_HOME" >> "$GITHUB_ENV" + echo "$COMPACT_HOME" >> "$GITHUB_PATH" + + echo "✅ Verifying installation..." + if [ ! -f "$COMPACT_HOME/compactc" ]; then + echo "::error::❌ compactc not found in $COMPACT_HOME" + exit 1 + fi + + echo "🤖 Testing installation..." + "$COMPACT_HOME/compactc" --version + + - name: Check compiler and language version + run: | + COMPILER_OUTPUT=$(compactc --version) + COMPUTED_COMPILER_VERSION=$(echo "$COMPILER_OUTPUT" | grep -oP '\b0\.[0-9]+\.[0-9]+\b' | head -n 1) + if [ "$COMPUTED_COMPILER_VERSION" != "$COMPILER_VERSION" ]; then + errMsg="❌ Compiler version mismatch!%0AExpected: $COMPILER_VERSION%0AGot: $COMPUTED_COMPILER_VERSION" + echo "::error::$errMsg" + exit 1 + fi + echo "✅ Compiler version matches: $COMPUTED_COMPILER_VERSION" + + LANGUAGE_OUTPUT=$(compactc --language-version) + COMPUTED_LANGUAGE_VERSION=$(echo "$LANGUAGE_OUTPUT" | grep -oP '\b0\.[0-9]+\.[0-9]+\b' | tail -n 1) + if [ "$COMPUTED_LANGUAGE_VERSION" != "$LANGUAGE_VERSION" ]; then + errMsg="❌ Language version mismatch!%0AExpected: $LANGUAGE_VERSION%0AGot: $COMPUTED_LANGUAGE_VERSION" + echo "::error::$errMsg" + exit 1 + fi + + echo "✅ Language version matches: $COMPUTED_LANGUAGE_VERSION" + + - name: Compile, test, and check types + run: turbo compact types test diff --git a/README.md b/README.md index d2fd5a06..fff600b6 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ## Installation -Make sure you have [nvm](https://github.com/nvm-sh/nvm) and [yarn](https://yarnpkg.com/getting-started/install) installed on your machine. +Make sure you have [nvm](https://github.com/nvm-sh/nvm), [yarn](https://yarnpkg.com/getting-started/install), and [turbo](https://turborepo.com/docs/getting-started/installation) installed on your machine. Follow Midnight's [compact installation guide](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) and confirm that `compactc` is in the `PATH` env variable. @@ -28,6 +28,7 @@ Usage: compactc.bin ... > > - [node](https://nodejs.org/) > - [yarn](https://yarnpkg.com/getting-started/install) +> - [turbo](https://turborepo.com/docs/getting-started/installation) > - [compact](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) Clone the repository: @@ -41,7 +42,7 @@ git clone git@github.com:OpenZeppelin/midnight-contracts.git ```bash nvm install && \ yarn && \ -yarn prepare +turbo compact ``` ## Usage @@ -49,7 +50,7 @@ yarn prepare ### Compile the contracts ```bash -$ npx turbo compact +$ turbo compact (...) ✔ [COMPILE] [1/2] Compiled ERC20.compact @@ -87,13 +88,24 @@ Cached: 0 cached, 2 total **Note:** Speed up the development process by skipping the prover and verifier key file generation: ```bash -npx turbo compact -- --skip-zk +turbo compact -- --skip-zk ``` ### Run tests ```bash -npx turbo test +turbo test +``` + +### Format and lint files + +```bash +turbo fmt-and-lint:fix +``` + +### All together now! +```bash +turbo compact test fmt-and-lint:fix ``` ## Security diff --git a/compact/package.json b/compact/package.json index b7cb4957..dca0a1dd 100644 --- a/compact/package.json +++ b/compact/package.json @@ -22,7 +22,7 @@ "clean": "git clean -fXd" }, "devDependencies": { - "@types/node": "^22.14.0", + "@types/node": "22.14.0", "fast-check": "^3.15.0", "typescript": "^5.8.2" }, diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 74fc46b2..37c54380 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -24,9 +24,7 @@ "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" }, "devDependencies": { - "@openzeppelin-midnight/compact": "workspace:^", - "@biomejs/biome": "1.9.4", - "@types/node": "^22.14.0", + "@types/node": "22.14.0", "ts-node": "^10.9.2", "typescript": "^5.2.2", "vitest": "^3.1.3" diff --git a/package.json b/package.json index 953ee192..c27e082a 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,6 @@ "packageManager": "yarn@4.1.0", "workspaces": ["compact/", "contracts/*/", "docs/"], "scripts": { - "prepare": "npx tsc -p ./compact && yarn rebuild", "docs": "npx turbo run docs --filter=docs", "docs:watch": "npx turbo run docs:watch --filter=docs", "compact": "turbo run compact", diff --git a/turbo.json b/turbo.json index d398fa4b..d19f046b 100644 --- a/turbo.json +++ b/turbo.json @@ -2,12 +2,14 @@ "$schema": "https://turbo.build/schema.json", "tasks": { "compact": { + "dependsOn": ["^build"], "env": ["COMPACT_HOME"], "inputs": ["src/**/*.compact"], "outputLogs": "new-only", "outputs": ["src/artifacts/**", "src/gen/**", "gen/**"] }, "test": { + "dependsOn": ["^build", "compact"], "outputs": [], "cache": false }, @@ -25,6 +27,7 @@ "outputs": ["dist/**"] }, "types": { + "dependsOn": ["compact"], "outputs": [], "cache": false }, diff --git a/yarn.lock b/yarn.lock index 344bcd1c..db9792d6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -392,7 +392,7 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/compact@workspace:compact" dependencies: - "@types/node": "npm:^22.14.0" + "@types/node": "npm:22.14.0" chalk: "npm:^5.4.1" fast-check: "npm:^3.15.0" log-symbols: "npm:^7.0.0" @@ -408,22 +408,8 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/erc20@workspace:contracts/erc20" dependencies: - "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" - "@types/node": "npm:^22.14.0" - ts-node: "npm:^10.9.2" - typescript: "npm:^5.2.2" - vitest: "npm:^3.1.3" - languageName: unknown - linkType: soft - -"@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken": - version: 0.0.0-use.local - resolution: "@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken" - dependencies: - "@biomejs/biome": "npm:1.9.4" - "@openzeppelin-midnight/compact": "workspace:^" - "@types/node": "npm:^22.14.0" + "@types/node": "npm:22.14.0" ts-node: "npm:^10.9.2" typescript: "npm:^5.2.2" vitest: "npm:^3.1.3" @@ -434,9 +420,8 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" dependencies: - "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" - "@types/node": "npm:^18.18.6" + "@types/node": "npm:22.14.0" ts-node: "npm:^10.9.2" typescript: "npm:^5.2.2" vitest: "npm:^3.1.3" @@ -644,21 +629,21 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^18.18.6": - version: 18.19.87 - resolution: "@types/node@npm:18.19.87" +"@types/node@npm:22.14.0": + version: 22.14.0 + resolution: "@types/node@npm:22.14.0" dependencies: - undici-types: "npm:~5.26.4" - checksum: 10/1e71b6d16dedeaa1fd5ff55baf1f353ca1f9e673b2e482d7fe82fa685addea5159a36602a344784c989b5e07ca1be633d0c493adf5951dee5a29cee69d613e7f + undici-types: "npm:~6.21.0" + checksum: 10/d0669a8a37a18532c886ccfa51eb3fe1e46088deb4d3d27ebcd5d7d68bd6343ad1c7a3fcb85164780a57629359c33a6c917ecff748ea232bceac7692acc96537 languageName: node linkType: hard -"@types/node@npm:^22.14.0": - version: 22.15.21 - resolution: "@types/node@npm:22.15.21" +"@types/node@npm:^22": + version: 22.15.19 + resolution: "@types/node@npm:22.15.19" dependencies: undici-types: "npm:~6.21.0" - checksum: 10/cb4189587cca445bfb8166c0ed39f9344d743f37f3da892f2999a99bbabda45dc773237e61ecb7d1dc83dd95718cb1b5715b0be5dd7953565b19019e36a7cf39 + checksum: 10/02311c2b5dbf2e9e2c17497dc27858bcefbe12a81af0d9b81f865613d8d014726e0eb6cbebfbdb84a327c1b9f9da1347a65a7699ac58c8854fb4daf447031149 languageName: node linkType: hard From d6d7d95bcdcd897ec322304dc3278bc32634811e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 10:02:16 -0400 Subject: [PATCH 224/282] Update Yarn.lock --- yarn.lock | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/yarn.lock b/yarn.lock index db9792d6..a038bf32 100644 --- a/yarn.lock +++ b/yarn.lock @@ -416,12 +416,26 @@ __metadata: languageName: unknown linkType: soft +"@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken": + version: 0.0.0-use.local + resolution: "@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken" + dependencies: + "@biomejs/biome": "npm:1.9.4" + "@openzeppelin-midnight/compact": "workspace:^" + "@types/node": "npm:^22.14.0" + ts-node: "npm:^10.9.2" + typescript: "npm:^5.2.2" + vitest: "npm:^3.1.3" + languageName: unknown + linkType: soft + "@openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" dependencies: "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:22.14.0" + "@types/node": "npm:22.14.0" ts-node: "npm:^10.9.2" typescript: "npm:^5.2.2" vitest: "npm:^3.1.3" @@ -629,11 +643,16 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:22.14.0": + version: 22.14.0 + resolution: "@types/node@npm:22.14.0" "@types/node@npm:22.14.0": version: 22.14.0 resolution: "@types/node@npm:22.14.0" dependencies: undici-types: "npm:~6.21.0" + checksum: 10/d0669a8a37a18532c886ccfa51eb3fe1e46088deb4d3d27ebcd5d7d68bd6343ad1c7a3fcb85164780a57629359c33a6c917ecff748ea232bceac7692acc96537 + undici-types: "npm:~6.21.0" checksum: 10/d0669a8a37a18532c886ccfa51eb3fe1e46088deb4d3d27ebcd5d7d68bd6343ad1c7a3fcb85164780a57629359c33a6c917ecff748ea232bceac7692acc96537 languageName: node linkType: hard @@ -647,6 +666,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^22.14.0": + version: 22.15.32 + resolution: "@types/node@npm:22.15.32" + dependencies: + undici-types: "npm:~6.21.0" + checksum: 10/10b4c106d0c512a1d35ec08142bd7fb5cf2e1df93fc5627b3c69dd843dec4be07a47f1fa7ede232ad84762d75a372ea35028b79ee1e753b6f2adecd0b2cb2f71 + languageName: node + linkType: hard + "@types/object-inspect@npm:^1.8.1": version: 1.13.0 resolution: "@types/object-inspect@npm:1.13.0" From d74724fa628a2bc45d83c4fc3fcd82c430be4476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 10:08:28 -0400 Subject: [PATCH 225/282] Document storage vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Iskander Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- .../src/NonFungibleToken.compact | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index cf6790ed..f78fe3a0 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -46,10 +46,51 @@ module NonFungibleToken { /// Public state export sealed ledger _name: Opaque<"string">; export sealed ledger _symbol: Opaque<"string">; + + /** + * @description Mapping from token IDs to their owner addresses. + * @type {Uint<128>} tokenId - The unique identifier for a token. + * @type {Either} owner - The owner address (public key or contract). + * @type {Map} + * @type {Map, Either>} _owners + */ export ledger _owners: Map, Either>; + + /** + * @description Mapping from account addresses to their token balances. + * @type {Either} owner - The owner address. + * @type {Uint<128>} balance - The balance of the owner. + * @type {Map} + * @type {Map, Uint<128>>} _balances + */ export ledger _balances: Map, Uint<128>>; + + /** + * @description Mapping from token IDs to approved addresses. + * @type {Uint<128>} tokenId - The unique identifier for a token. + * @type {Either} approved - The approved address (public key or contract). + * @type {Map} + * @type {Map, Either>} _tokenApprovals + */ export ledger _tokenApprovals: Map, Either>; + + /** + * @description Mapping from owner addresses to operator approvals. + * @type {Either} owner - The owner address. + * @type {Either} operator - The operator address. + * @type {Boolean} approved - Whether the operator is approved. + * @type {Map>} + * @type {Map, Map, Boolean>>} _operatorApprovals + */ export ledger _operatorApprovals: Map, Map, Boolean>>; + + /** + * @description Mapping from token IDs to their metadata URIs. + * @type {Uint<128>} tokenId - The unique identifier for a token. + * @type {Opaque<"string">} uri - The metadata URI for the token. + * @type {Map} + * @type {Map, Opaque<"string">>} _tokenURIs + */ export ledger _tokenURIs: Map, Opaque<"string">>; /** From 9254a5c1ec7e0830225dc9bfc193564f3ac4d9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 10:09:20 -0400 Subject: [PATCH 226/282] Fmt method signature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Iskander Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- contracts/nonFungibleToken/src/NonFungibleToken.compact | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index f78fe3a0..83711680 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -103,10 +103,7 @@ module NonFungibleToken { * @param {Opaque<"string">} symbol_ - The symbol of the token. * @return {[]} - None. */ - export circuit initialize( - name_: Opaque<"string">, - symbol_: Opaque<"string"> - ): [] { + export circuit initialize(name_: Opaque<"string">, symbol_: Opaque<"string">): [] { Initializable_initialize(); _name = name_; _symbol = symbol_; From 3aa2a16a2643721681f3e0b9f3191583234a3637 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 6 Jun 2025 13:02:01 -0400 Subject: [PATCH 227/282] Add extensibility section (#86) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Iskander <0xisk@proton.me> Co-authored-by: Iskander Co-authored-by: Emanuel Solis Co-authored-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index fff600b6..0e1a8785 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ Usage: compactc.bin ... > > - [node](https://nodejs.org/) > - [yarn](https://yarnpkg.com/getting-started/install) -> - [turbo](https://turborepo.com/docs/getting-started/installation) > - [compact](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) Clone the repository: From 56e03c7c15ad0b37156fde99263f1185682c623d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 01:09:45 -0400 Subject: [PATCH 228/282] Adds CI Tests, Lints, Compile, Build (#113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> Co-authored-by: Andrew Fleming --- README.md | 1 + yarn.lock | 29 +---------------------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 0e1a8785..fff600b6 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Usage: compactc.bin ... > > - [node](https://nodejs.org/) > - [yarn](https://yarnpkg.com/getting-started/install) +> - [turbo](https://turborepo.com/docs/getting-started/installation) > - [compact](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) Clone the repository: diff --git a/yarn.lock b/yarn.lock index a038bf32..53c83341 100644 --- a/yarn.lock +++ b/yarn.lock @@ -392,6 +392,7 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/compact@workspace:compact" dependencies: + "@types/node": "npm:22.14.0" "@types/node": "npm:22.14.0" chalk: "npm:^5.4.1" fast-check: "npm:^3.15.0" @@ -416,26 +417,12 @@ __metadata: languageName: unknown linkType: soft -"@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken": - version: 0.0.0-use.local - resolution: "@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken" - dependencies: - "@biomejs/biome": "npm:1.9.4" - "@openzeppelin-midnight/compact": "workspace:^" - "@types/node": "npm:^22.14.0" - ts-node: "npm:^10.9.2" - typescript: "npm:^5.2.2" - vitest: "npm:^3.1.3" - languageName: unknown - linkType: soft - "@openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" dependencies: "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:22.14.0" - "@types/node": "npm:22.14.0" ts-node: "npm:^10.9.2" typescript: "npm:^5.2.2" vitest: "npm:^3.1.3" @@ -643,16 +630,11 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:22.14.0": - version: 22.14.0 - resolution: "@types/node@npm:22.14.0" "@types/node@npm:22.14.0": version: 22.14.0 resolution: "@types/node@npm:22.14.0" dependencies: undici-types: "npm:~6.21.0" - checksum: 10/d0669a8a37a18532c886ccfa51eb3fe1e46088deb4d3d27ebcd5d7d68bd6343ad1c7a3fcb85164780a57629359c33a6c917ecff748ea232bceac7692acc96537 - undici-types: "npm:~6.21.0" checksum: 10/d0669a8a37a18532c886ccfa51eb3fe1e46088deb4d3d27ebcd5d7d68bd6343ad1c7a3fcb85164780a57629359c33a6c917ecff748ea232bceac7692acc96537 languageName: node linkType: hard @@ -666,15 +648,6 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^22.14.0": - version: 22.15.32 - resolution: "@types/node@npm:22.15.32" - dependencies: - undici-types: "npm:~6.21.0" - checksum: 10/10b4c106d0c512a1d35ec08142bd7fb5cf2e1df93fc5627b3c69dd843dec4be07a47f1fa7ede232ad84762d75a372ea35028b79ee1e753b6f2adecd0b2cb2f71 - languageName: node - linkType: hard - "@types/object-inspect@npm:^1.8.1": version: 1.13.0 resolution: "@types/object-inspect@npm:1.13.0" From 3c49aae7cd056229cd8233753bbca9fcca6e30f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 10:31:40 -0400 Subject: [PATCH 229/282] Update yarn.lock --- yarn.lock | 732 +++++++++++++++++++++++++++++------------------------- 1 file changed, 387 insertions(+), 345 deletions(-) diff --git a/yarn.lock b/yarn.lock index 53c83341..6aca94eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -105,185 +105,185 @@ __metadata: languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/aix-ppc64@npm:0.25.4" +"@esbuild/aix-ppc64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/aix-ppc64@npm:0.25.5" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/android-arm64@npm:0.25.4" +"@esbuild/android-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-arm64@npm:0.25.5" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/android-arm@npm:0.25.4" +"@esbuild/android-arm@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-arm@npm:0.25.5" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/android-x64@npm:0.25.4" +"@esbuild/android-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-x64@npm:0.25.5" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/darwin-arm64@npm:0.25.4" +"@esbuild/darwin-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/darwin-arm64@npm:0.25.5" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/darwin-x64@npm:0.25.4" +"@esbuild/darwin-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/darwin-x64@npm:0.25.5" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/freebsd-arm64@npm:0.25.4" +"@esbuild/freebsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/freebsd-arm64@npm:0.25.5" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/freebsd-x64@npm:0.25.4" +"@esbuild/freebsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/freebsd-x64@npm:0.25.5" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-arm64@npm:0.25.4" +"@esbuild/linux-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-arm64@npm:0.25.5" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-arm@npm:0.25.4" +"@esbuild/linux-arm@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-arm@npm:0.25.5" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-ia32@npm:0.25.4" +"@esbuild/linux-ia32@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-ia32@npm:0.25.5" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-loong64@npm:0.25.4" +"@esbuild/linux-loong64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-loong64@npm:0.25.5" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-mips64el@npm:0.25.4" +"@esbuild/linux-mips64el@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-mips64el@npm:0.25.5" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-ppc64@npm:0.25.4" +"@esbuild/linux-ppc64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-ppc64@npm:0.25.5" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-riscv64@npm:0.25.4" +"@esbuild/linux-riscv64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-riscv64@npm:0.25.5" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-s390x@npm:0.25.4" +"@esbuild/linux-s390x@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-s390x@npm:0.25.5" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/linux-x64@npm:0.25.4" +"@esbuild/linux-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-x64@npm:0.25.5" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/netbsd-arm64@npm:0.25.4" +"@esbuild/netbsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/netbsd-arm64@npm:0.25.5" conditions: os=netbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/netbsd-x64@npm:0.25.4" +"@esbuild/netbsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/netbsd-x64@npm:0.25.5" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/openbsd-arm64@npm:0.25.4" +"@esbuild/openbsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/openbsd-arm64@npm:0.25.5" conditions: os=openbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/openbsd-x64@npm:0.25.4" +"@esbuild/openbsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/openbsd-x64@npm:0.25.5" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/sunos-x64@npm:0.25.4" +"@esbuild/sunos-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/sunos-x64@npm:0.25.5" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/win32-arm64@npm:0.25.4" +"@esbuild/win32-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-arm64@npm:0.25.5" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/win32-ia32@npm:0.25.4" +"@esbuild/win32-ia32@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-ia32@npm:0.25.5" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.25.4": - version: 0.25.4 - resolution: "@esbuild/win32-x64@npm:0.25.4" +"@esbuild/win32-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-x64@npm:0.25.5" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@frangio/servbot@npm:^0.2.5": - version: 0.2.5 - resolution: "@frangio/servbot@npm:0.2.5" - checksum: 10/9c40bf898610efbbcc6529a5b4fe599d556aa7e74efa5591829f37be909b7aee4fe80660eb7dc04e1611547210d7ed65e29b0228a9a4271b30af54158e89ff88 +"@frangio/servbot@npm:^0.3.0-1": + version: 0.3.0-1 + resolution: "@frangio/servbot@npm:0.3.0-1" + checksum: 10/db923a976dfcf250650ff7793e46c4221504ca632a68ccbd0873224d72adabcbfb1790c849dc8a24067ea54451dac2a634b709db72664df086e4b342a9cd87fd languageName: node linkType: hard @@ -392,7 +392,6 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/compact@workspace:compact" dependencies: - "@types/node": "npm:22.14.0" "@types/node": "npm:22.14.0" chalk: "npm:^5.4.1" fast-check: "npm:^3.15.0" @@ -430,10 +429,10 @@ __metadata: linkType: soft "@openzeppelin/docs-utils@npm:^0.1.5": - version: 0.1.5 - resolution: "@openzeppelin/docs-utils@npm:0.1.5" + version: 0.1.6 + resolution: "@openzeppelin/docs-utils@npm:0.1.6" dependencies: - "@frangio/servbot": "npm:^0.2.5" + "@frangio/servbot": "npm:^0.3.0-1" chalk: "npm:^3.0.0" chokidar: "npm:^3.5.3" env-paths: "npm:^2.2.0" @@ -444,7 +443,7 @@ __metadata: minimist: "npm:^1.2.0" bin: oz-docs: oz-docs.js - checksum: 10/08f1fc03f4d8e71e3000b501ea2536bdd065f44e5411c32ee1afc084e12075d4b65e5747556b60b63c57abe79718c292dad6c75cdb4fdf260d26570b7497eb58 + checksum: 10/7e141cdd205af152191b7cb935f1d015543d0bc5109ecad07808ebdd13c3abaa21363ba844d59e635fcfd3792544ec236950ac24a4932a01bd1bdd6094b46b3b languageName: node linkType: hard @@ -455,142 +454,142 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.40.2" +"@rollup/rollup-android-arm-eabi@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.43.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-android-arm64@npm:4.40.2" +"@rollup/rollup-android-arm64@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-android-arm64@npm:4.43.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-darwin-arm64@npm:4.40.2" +"@rollup/rollup-darwin-arm64@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.43.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-darwin-x64@npm:4.40.2" +"@rollup/rollup-darwin-x64@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.43.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.40.2" +"@rollup/rollup-freebsd-arm64@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.43.0" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-freebsd-x64@npm:4.40.2" +"@rollup/rollup-freebsd-x64@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.43.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.40.2" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.43.0" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.40.2" +"@rollup/rollup-linux-arm-musleabihf@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.43.0" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.40.2" +"@rollup/rollup-linux-arm64-gnu@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.43.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.40.2" +"@rollup/rollup-linux-arm64-musl@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.43.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-loongarch64-gnu@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.40.2" +"@rollup/rollup-linux-loongarch64-gnu@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.43.0" conditions: os=linux & cpu=loong64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-powerpc64le-gnu@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.40.2" +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.43.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.40.2" +"@rollup/rollup-linux-riscv64-gnu@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.43.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-musl@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.40.2" +"@rollup/rollup-linux-riscv64-musl@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.43.0" conditions: os=linux & cpu=riscv64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.40.2" +"@rollup/rollup-linux-s390x-gnu@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.43.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.40.2" +"@rollup/rollup-linux-x64-gnu@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.43.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.40.2" +"@rollup/rollup-linux-x64-musl@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.43.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.40.2" +"@rollup/rollup-win32-arm64-msvc@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.43.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.40.2" +"@rollup/rollup-win32-ia32-msvc@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.43.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.40.2": - version: 4.40.2 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.40.2" +"@rollup/rollup-win32-x64-msvc@npm:4.43.0": + version: 4.43.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.43.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -623,13 +622,36 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:1.0.7, @types/estree@npm:^1.0.0": +"@types/chai@npm:^5.2.2": + version: 5.2.2 + resolution: "@types/chai@npm:5.2.2" + dependencies: + "@types/deep-eql": "npm:*" + checksum: 10/de425e7b02cc1233a93923866e019dffbafa892774813940b780ebb1ac9f8a8c57b7438c78686bf4e5db05cd3fc8a970fedf6b83638543995ecca88ef2060668 + languageName: node + linkType: hard + +"@types/deep-eql@npm:*": + version: 4.0.2 + resolution: "@types/deep-eql@npm:4.0.2" + checksum: 10/249a27b0bb22f6aa28461db56afa21ec044fa0e303221a62dff81831b20c8530502175f1a49060f7099e7be06181078548ac47c668de79ff9880241968d43d0c + languageName: node + linkType: hard + +"@types/estree@npm:1.0.7": version: 1.0.7 resolution: "@types/estree@npm:1.0.7" checksum: 10/419c845ece767ad4b21171e6e5b63dabb2eb46b9c0d97361edcd9cabbf6a95fcadb91d89b5fa098d1336fa0b8fceaea82fca97a2ef3971f5c86e53031e157b21 languageName: node linkType: hard +"@types/estree@npm:^1.0.0": + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099 + languageName: node + linkType: hard + "@types/node@npm:22.14.0": version: 22.14.0 resolution: "@types/node@npm:22.14.0" @@ -639,12 +661,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^22": - version: 22.15.19 - resolution: "@types/node@npm:22.15.19" +"@types/node@npm:^22, @types/node@npm:^22.14.0": + version: 22.15.32 + resolution: "@types/node@npm:22.15.32" dependencies: undici-types: "npm:~6.21.0" - checksum: 10/02311c2b5dbf2e9e2c17497dc27858bcefbe12a81af0d9b81f865613d8d014726e0eb6cbebfbdb84a327c1b9f9da1347a65a7699ac58c8854fb4daf447031149 + checksum: 10/10b4c106d0c512a1d35ec08142bd7fb5cf2e1df93fc5627b3c69dd843dec4be07a47f1fa7ede232ad84762d75a372ea35028b79ee1e753b6f2adecd0b2cb2f71 languageName: node linkType: hard @@ -655,84 +677,86 @@ __metadata: languageName: node linkType: hard -"@vitest/expect@npm:3.1.3": - version: 3.1.3 - resolution: "@vitest/expect@npm:3.1.3" +"@vitest/expect@npm:3.2.4": + version: 3.2.4 + resolution: "@vitest/expect@npm:3.2.4" dependencies: - "@vitest/spy": "npm:3.1.3" - "@vitest/utils": "npm:3.1.3" + "@types/chai": "npm:^5.2.2" + "@vitest/spy": "npm:3.2.4" + "@vitest/utils": "npm:3.2.4" chai: "npm:^5.2.0" tinyrainbow: "npm:^2.0.0" - checksum: 10/f63053849430e93e85cd50994a75f32e6b73d35fefbf7894f1869c356ed6c601adfc95c66004b2df3c49335300202286480c47d841d78d2047af6bee00f8b3ed + checksum: 10/dc69ce886c13714dfbbff78f2d2cb7eb536017e82301a73c42d573a9e9d2bf91005ac7abd9b977adf0a3bd431209f45a8ac2418029b68b0a377e092607c843ce languageName: node linkType: hard -"@vitest/mocker@npm:3.1.3": - version: 3.1.3 - resolution: "@vitest/mocker@npm:3.1.3" +"@vitest/mocker@npm:3.2.4": + version: 3.2.4 + resolution: "@vitest/mocker@npm:3.2.4" dependencies: - "@vitest/spy": "npm:3.1.3" + "@vitest/spy": "npm:3.2.4" estree-walker: "npm:^3.0.3" magic-string: "npm:^0.30.17" peerDependencies: msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 peerDependenciesMeta: msw: optional: true vite: optional: true - checksum: 10/fc4a8ee015551f476af56ee27327c78fd6f8a023eea79a92834482d10272c74dd0a39631b2d55341e54ac04803b1d2710527b34ed206ede18cde9706a1582ed8 + checksum: 10/5e92431b6ed9fc1679060e4caef3e4623f4750542a5d7cd944774f8217c4d231e273202e8aea00bab33260a5a9222ecb7005d80da0348c3c829bd37d123071a8 languageName: node linkType: hard -"@vitest/pretty-format@npm:3.1.3, @vitest/pretty-format@npm:^3.1.3": - version: 3.1.3 - resolution: "@vitest/pretty-format@npm:3.1.3" +"@vitest/pretty-format@npm:3.2.4, @vitest/pretty-format@npm:^3.2.4": + version: 3.2.4 + resolution: "@vitest/pretty-format@npm:3.2.4" dependencies: tinyrainbow: "npm:^2.0.0" - checksum: 10/da508750f47b4043e9aaea803f37dada4d3121b63a8fd2a7c77849a380d9040ca488291f6ee98e7ee3e6543bd6c2ed7cdad99b6b86897999c740462ef617413a + checksum: 10/8dd30cbf956e01fbab042fe651fb5175d9f0cd00b7b569a46cd98df89c4fec47dab12916201ad6e09a4f25f2a2ec8927a4bfdc61118593097f759c90b18a51d4 languageName: node linkType: hard -"@vitest/runner@npm:3.1.3": - version: 3.1.3 - resolution: "@vitest/runner@npm:3.1.3" +"@vitest/runner@npm:3.2.4": + version: 3.2.4 + resolution: "@vitest/runner@npm:3.2.4" dependencies: - "@vitest/utils": "npm:3.1.3" + "@vitest/utils": "npm:3.2.4" pathe: "npm:^2.0.3" - checksum: 10/7862077b7663200801cd7903b977b3713a291f91b2b0930ee59951bec0ae51d38219308e543b62ff5eaed9ead51bcbd7175b19f9b7c0d876e2975defee76fdee + strip-literal: "npm:^3.0.0" + checksum: 10/197bd55def519ef202f990b7c1618c212380831827c116240871033e4973decb780503c705ba9245a12bd8121f3ac4086ffcb3e302148b62d9bd77fd18dd1deb languageName: node linkType: hard -"@vitest/snapshot@npm:3.1.3": - version: 3.1.3 - resolution: "@vitest/snapshot@npm:3.1.3" +"@vitest/snapshot@npm:3.2.4": + version: 3.2.4 + resolution: "@vitest/snapshot@npm:3.2.4" dependencies: - "@vitest/pretty-format": "npm:3.1.3" + "@vitest/pretty-format": "npm:3.2.4" magic-string: "npm:^0.30.17" pathe: "npm:^2.0.3" - checksum: 10/5889414ecd19df6a1cc09c57fc96d344721f01e5812d9153565208c76dac4d42fc1c636153b9701d50a1d5acd4fd8ce81c09c9592d97728a700c5a8af790d0a4 + checksum: 10/acfb682491b9ca9345bf9fed02c2779dec43e0455a380c1966b0aad8dd81c79960902cf34621ab48fe80a0eaf8c61cc42dec186a1321dc3c9897ef2ebd5f1bc4 languageName: node linkType: hard -"@vitest/spy@npm:3.1.3": - version: 3.1.3 - resolution: "@vitest/spy@npm:3.1.3" +"@vitest/spy@npm:3.2.4": + version: 3.2.4 + resolution: "@vitest/spy@npm:3.2.4" dependencies: - tinyspy: "npm:^3.0.2" - checksum: 10/9b42e219b40fde935e5bd7fa19ee99f01fc27ecd89a5fccabbbbc91e02eef3bd0530ba3769c2ff380529f708eb535a30cce773d680c708209a994c54d1d992fe + tinyspy: "npm:^4.0.3" + checksum: 10/7d38c299f42a8c7e5e41652b203af98ca54e63df69c3b072d0e401d5a57fbbba3e39d8538ac1b3022c26718a6388d0bcc222bc2f07faab75942543b9247c007d languageName: node linkType: hard -"@vitest/utils@npm:3.1.3": - version: 3.1.3 - resolution: "@vitest/utils@npm:3.1.3" +"@vitest/utils@npm:3.2.4": + version: 3.2.4 + resolution: "@vitest/utils@npm:3.2.4" dependencies: - "@vitest/pretty-format": "npm:3.1.3" - loupe: "npm:^3.1.3" + "@vitest/pretty-format": "npm:3.2.4" + loupe: "npm:^3.1.4" tinyrainbow: "npm:^2.0.0" - checksum: 10/d9971948161364e61e0fb08a053b9768f02054686f0a74e5b7bdc9c726271842d5f8c4256c68cf9aad2b83a28d2333c5694e336715d145e194fa1a93e64e97c3 + checksum: 10/7f12ef63bd8ee13957744d1f336b0405f164ade4358bf9dfa531f75bbb58ffac02bf61aba65724311ddbc50b12ba54853a169e59c6b837c16086173b9a480710 languageName: node linkType: hard @@ -753,11 +777,11 @@ __metadata: linkType: hard "acorn@npm:^8.11.0, acorn@npm:^8.4.1": - version: 8.14.1 - resolution: "acorn@npm:8.14.1" + version: 8.15.0 + resolution: "acorn@npm:8.15.0" bin: acorn: bin/acorn - checksum: 10/d1379bbee224e8d44c3c3946e6ba6973e999fbdd4e22e41c3455d7f9b6f72f7ce18d3dc218002e1e48eea789539cf1cb6d1430c81838c6744799c712fb557d92 + checksum: 10/77f2de5051a631cf1729c090e5759148459cdb76b5f5c70f890503d629cf5052357b0ce783c0f976dd8a93c5150f59f6d18df1def3f502396a20f81282482fa4 languageName: node linkType: hard @@ -846,11 +870,11 @@ __metadata: linkType: hard "brace-expansion@npm:^2.0.1": - version: 2.0.1 - resolution: "brace-expansion@npm:2.0.1" + version: 2.0.2 + resolution: "brace-expansion@npm:2.0.2" dependencies: balanced-match: "npm:^1.0.0" - checksum: 10/a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 + checksum: 10/01dff195e3646bc4b0d27b63d9bab84d2ebc06121ff5013ad6e5356daa5a9d6b60fa26cf73c74797f2dc3fbec112af13578d51f75228c1112b26c790a87b0488 languageName: node linkType: hard @@ -1003,7 +1027,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.3.4, debug@npm:^4.4.0": +"debug@npm:4, debug@npm:^4.3.4, debug@npm:^4.4.1": version: 4.4.1 resolution: "debug@npm:4.4.1" dependencies: @@ -1096,34 +1120,34 @@ __metadata: linkType: hard "esbuild@npm:^0.25.0": - version: 0.25.4 - resolution: "esbuild@npm:0.25.4" - dependencies: - "@esbuild/aix-ppc64": "npm:0.25.4" - "@esbuild/android-arm": "npm:0.25.4" - "@esbuild/android-arm64": "npm:0.25.4" - "@esbuild/android-x64": "npm:0.25.4" - "@esbuild/darwin-arm64": "npm:0.25.4" - "@esbuild/darwin-x64": "npm:0.25.4" - "@esbuild/freebsd-arm64": "npm:0.25.4" - "@esbuild/freebsd-x64": "npm:0.25.4" - "@esbuild/linux-arm": "npm:0.25.4" - "@esbuild/linux-arm64": "npm:0.25.4" - "@esbuild/linux-ia32": "npm:0.25.4" - "@esbuild/linux-loong64": "npm:0.25.4" - "@esbuild/linux-mips64el": "npm:0.25.4" - "@esbuild/linux-ppc64": "npm:0.25.4" - "@esbuild/linux-riscv64": "npm:0.25.4" - "@esbuild/linux-s390x": "npm:0.25.4" - "@esbuild/linux-x64": "npm:0.25.4" - "@esbuild/netbsd-arm64": "npm:0.25.4" - "@esbuild/netbsd-x64": "npm:0.25.4" - "@esbuild/openbsd-arm64": "npm:0.25.4" - "@esbuild/openbsd-x64": "npm:0.25.4" - "@esbuild/sunos-x64": "npm:0.25.4" - "@esbuild/win32-arm64": "npm:0.25.4" - "@esbuild/win32-ia32": "npm:0.25.4" - "@esbuild/win32-x64": "npm:0.25.4" + version: 0.25.5 + resolution: "esbuild@npm:0.25.5" + dependencies: + "@esbuild/aix-ppc64": "npm:0.25.5" + "@esbuild/android-arm": "npm:0.25.5" + "@esbuild/android-arm64": "npm:0.25.5" + "@esbuild/android-x64": "npm:0.25.5" + "@esbuild/darwin-arm64": "npm:0.25.5" + "@esbuild/darwin-x64": "npm:0.25.5" + "@esbuild/freebsd-arm64": "npm:0.25.5" + "@esbuild/freebsd-x64": "npm:0.25.5" + "@esbuild/linux-arm": "npm:0.25.5" + "@esbuild/linux-arm64": "npm:0.25.5" + "@esbuild/linux-ia32": "npm:0.25.5" + "@esbuild/linux-loong64": "npm:0.25.5" + "@esbuild/linux-mips64el": "npm:0.25.5" + "@esbuild/linux-ppc64": "npm:0.25.5" + "@esbuild/linux-riscv64": "npm:0.25.5" + "@esbuild/linux-s390x": "npm:0.25.5" + "@esbuild/linux-x64": "npm:0.25.5" + "@esbuild/netbsd-arm64": "npm:0.25.5" + "@esbuild/netbsd-x64": "npm:0.25.5" + "@esbuild/openbsd-arm64": "npm:0.25.5" + "@esbuild/openbsd-x64": "npm:0.25.5" + "@esbuild/sunos-x64": "npm:0.25.5" + "@esbuild/win32-arm64": "npm:0.25.5" + "@esbuild/win32-ia32": "npm:0.25.5" + "@esbuild/win32-x64": "npm:0.25.5" dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -1177,7 +1201,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10/227ffe9b31f0b184a0b0a0210bb9d32b2b115b8c5c9b09f08db2c3928cb470fc55a22dbba3c2894365d3abcc62c2089b85638be96a20691d1234d31990ea01b2 + checksum: 10/0fa4c3b42c6ddf1a008e75a4bb3dcab08ce22ac0b31dd59dc01f7fe8e21380bfaec07a2fe3730a7cf430da5a30142d016714b358666325a4733547afa42be405 languageName: node linkType: hard @@ -1223,15 +1247,15 @@ __metadata: languageName: node linkType: hard -"fdir@npm:^6.4.4": - version: 6.4.4 - resolution: "fdir@npm:6.4.4" +"fdir@npm:^6.4.4, fdir@npm:^6.4.6": + version: 6.4.6 + resolution: "fdir@npm:6.4.6" peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: picomatch: optional: true - checksum: 10/d0000d6b790059b35f4ed19acc8847a66452e0bc68b28766c929ffd523e5ec2083811fc8a545e4a1d4945ce70e887b3a610c145c681073b506143ae3076342ed + checksum: 10/c186ba387e7b75ccf874a098d9bc5fe0af0e9c52fc56f8eac8e80aa4edb65532684bf2bf769894ff90f53bf221d6136692052d31f07a9952807acae6cbe7ee50 languageName: node linkType: hard @@ -1485,6 +1509,13 @@ __metadata: languageName: node linkType: hard +"js-tokens@npm:^9.0.1": + version: 9.0.1 + resolution: "js-tokens@npm:9.0.1" + checksum: 10/3288ba73bb2023adf59501979fb4890feb6669cc167b13771b226814fde96a1583de3989249880e3f4d674040d1815685db9a9880db9153307480d39dc760365 + languageName: node + linkType: hard + "js-yaml@npm:^3.13.1": version: 3.14.1 resolution: "js-yaml@npm:3.14.1" @@ -1531,19 +1562,19 @@ __metadata: linkType: hard "log-symbols@npm:^7.0.0": - version: 7.0.0 - resolution: "log-symbols@npm:7.0.0" + version: 7.0.1 + resolution: "log-symbols@npm:7.0.1" dependencies: is-unicode-supported: "npm:^2.0.0" yoctocolors: "npm:^2.1.1" - checksum: 10/a6cb6e90bfe9f0774a09ff783e2035cd7e375a42757d7e401b391916a67f6da382f4966b57dda89430faaebe2ed13803ea867e104f8d67caf66082943a7153f0 + checksum: 10/0862313d84826b551582e39659b8586c56b65130c5f4f976420e2c23985228334f2a26fc4251ac22bf0a5b415d9430e86bf332557d934c10b036f9a549d63a09 languageName: node linkType: hard -"loupe@npm:^3.1.0, loupe@npm:^3.1.3": - version: 3.1.3 - resolution: "loupe@npm:3.1.3" - checksum: 10/9e98c34daf0eba48ccc603595e51f2ae002110982d84879cf78c51de2c632f0c571dfe82ce4210af60c32203d06b443465c269bda925076fe6d9b612cc65c321 +"loupe@npm:^3.1.0, loupe@npm:^3.1.4": + version: 3.1.4 + resolution: "loupe@npm:3.1.4" + checksum: 10/06ab1893731f167f2ce71f464a8a68372dc4cb807ecae20f9b844660c93813a298ca76bcd747ba6568b057af725ea63f0034ba3140c8f1d1fbb482d797e593ef languageName: node linkType: hard @@ -1704,7 +1735,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.8": +"nanoid@npm:^3.3.11": version: 3.3.11 resolution: "nanoid@npm:3.3.11" bin: @@ -1906,14 +1937,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.5.3": - version: 8.5.3 - resolution: "postcss@npm:8.5.3" +"postcss@npm:^8.5.5": + version: 8.5.6 + resolution: "postcss@npm:8.5.6" dependencies: - nanoid: "npm:^3.3.8" + nanoid: "npm:^3.3.11" picocolors: "npm:^1.1.1" source-map-js: "npm:^1.2.1" - checksum: 10/6d7e21a772e8b05bf102636918654dac097bac013f0dc8346b72ac3604fc16829646f94ea862acccd8f82e910b00e2c11c1f0ea276543565d278c7ca35516a7c + checksum: 10/9e4fbe97574091e9736d0e82a591e29aa100a0bf60276a926308f8c57249698935f35c5d2f4e80de778d0cbb8dcffab4f383d85fd50c5649aca421c3df729b86 languageName: node linkType: hard @@ -1967,30 +1998,30 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^4.34.9": - version: 4.40.2 - resolution: "rollup@npm:4.40.2" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.40.2" - "@rollup/rollup-android-arm64": "npm:4.40.2" - "@rollup/rollup-darwin-arm64": "npm:4.40.2" - "@rollup/rollup-darwin-x64": "npm:4.40.2" - "@rollup/rollup-freebsd-arm64": "npm:4.40.2" - "@rollup/rollup-freebsd-x64": "npm:4.40.2" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.40.2" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.40.2" - "@rollup/rollup-linux-arm64-gnu": "npm:4.40.2" - "@rollup/rollup-linux-arm64-musl": "npm:4.40.2" - "@rollup/rollup-linux-loongarch64-gnu": "npm:4.40.2" - "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.40.2" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.40.2" - "@rollup/rollup-linux-riscv64-musl": "npm:4.40.2" - "@rollup/rollup-linux-s390x-gnu": "npm:4.40.2" - "@rollup/rollup-linux-x64-gnu": "npm:4.40.2" - "@rollup/rollup-linux-x64-musl": "npm:4.40.2" - "@rollup/rollup-win32-arm64-msvc": "npm:4.40.2" - "@rollup/rollup-win32-ia32-msvc": "npm:4.40.2" - "@rollup/rollup-win32-x64-msvc": "npm:4.40.2" +"rollup@npm:^4.40.0": + version: 4.43.0 + resolution: "rollup@npm:4.43.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.43.0" + "@rollup/rollup-android-arm64": "npm:4.43.0" + "@rollup/rollup-darwin-arm64": "npm:4.43.0" + "@rollup/rollup-darwin-x64": "npm:4.43.0" + "@rollup/rollup-freebsd-arm64": "npm:4.43.0" + "@rollup/rollup-freebsd-x64": "npm:4.43.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.43.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.43.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.43.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.43.0" + "@rollup/rollup-linux-loongarch64-gnu": "npm:4.43.0" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.43.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.43.0" + "@rollup/rollup-linux-riscv64-musl": "npm:4.43.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.43.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.43.0" + "@rollup/rollup-linux-x64-musl": "npm:4.43.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.43.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.43.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.43.0" "@types/estree": "npm:1.0.7" fsevents: "npm:~2.3.2" dependenciesMeta: @@ -2038,7 +2069,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10/ab767c56e37410257864e051fccbdaf448ac7774129bf39295de716af816c49e0247e72749959969efbd892fc64e096880fa269764adf765579100e81abf5e7c + checksum: 10/c7f436880dfd5bd54e9ac579625b5355be58b5437ebb386eb88d709d6bed733a4411673cc80fd64dc5514cd71794544bc83775842108c86ed2b51827e11b33b8 languageName: node linkType: hard @@ -2107,12 +2138,12 @@ __metadata: linkType: hard "socks@npm:^2.8.3": - version: 2.8.4 - resolution: "socks@npm:2.8.4" + version: 2.8.5 + resolution: "socks@npm:2.8.5" dependencies: ip-address: "npm:^9.0.5" smart-buffer: "npm:^4.2.0" - checksum: 10/ab3af97aeb162f32c80e176c717ccf16a11a6ebb4656a62b94c0f96495ea2a1f4a8206c04b54438558485d83d0c5f61920c07a1a5d3963892a589b40cc6107dd + checksum: 10/0109090ec2bcb8d12d3875a987e85539ed08697500ad971a603c3057e4c266b4bf6a603e07af6d19218c422dd9b72d923aaa6c1f20abae275510bba458e4ccc9 languageName: node linkType: hard @@ -2218,6 +2249,15 @@ __metadata: languageName: node linkType: hard +"strip-literal@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-literal@npm:3.0.0" + dependencies: + js-tokens: "npm:^9.0.1" + checksum: 10/da1616f654f3ff481e078597b4565373a5eeed78b83de4a11a1a1b98292a9036f2474e528eff19b6eed93370428ff957a473827057c117495086436725d7efad + languageName: node + linkType: hard + "supports-color@npm:^7.1.0": version: 7.2.0 resolution: "supports-color@npm:7.2.0" @@ -2255,20 +2295,20 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.13": - version: 0.2.13 - resolution: "tinyglobby@npm:0.2.13" +"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.14": + version: 0.2.14 + resolution: "tinyglobby@npm:0.2.14" dependencies: fdir: "npm:^6.4.4" picomatch: "npm:^4.0.2" - checksum: 10/b04557ee58ad2be5f2d2cbb4b441476436c92bb45ba2e1fc464d686b793392b305ed0bcb8b877429e9b5036bdd46770c161a08384c0720b6682b7cd6ac80e403 + checksum: 10/3d306d319718b7cc9d79fb3f29d8655237aa6a1f280860a217f93417039d0614891aee6fc47c5db315f4fcc6ac8d55eb8e23e2de73b2c51a431b42456d9e5764 languageName: node linkType: hard -"tinypool@npm:^1.0.2": - version: 1.0.2 - resolution: "tinypool@npm:1.0.2" - checksum: 10/6109322f14b3763f65c8fa49fddab72cd3edd96b82dd50e05e63de74867329ff5353bff4377281ec963213d9314f37f4a353e9ee34bbac85fd4c1e4a568d6076 +"tinypool@npm:^1.1.1": + version: 1.1.1 + resolution: "tinypool@npm:1.1.1" + checksum: 10/0d54139e9dbc6ef33349768fa78890a4d708d16a7ab68e4e4ef3bb740609ddf0f9fd13292c2f413fbba756166c97051a657181c8f7ae92ade690604f183cc01d languageName: node linkType: hard @@ -2279,10 +2319,10 @@ __metadata: languageName: node linkType: hard -"tinyspy@npm:^3.0.2": - version: 3.0.2 - resolution: "tinyspy@npm:3.0.2" - checksum: 10/5db671b2ff5cd309de650c8c4761ca945459d7204afb1776db9a04fb4efa28a75f08517a8620c01ee32a577748802231ad92f7d5b194dc003ee7f987a2a06337 +"tinyspy@npm:^4.0.3": + version: 4.0.3 + resolution: "tinyspy@npm:4.0.3" + checksum: 10/b6a3ed40dd76a2b3c020250cf1401506b456509d1fb9dba0c7b0e644d258dac722843b85c57ccc36c8687db1e7978cb6adcc43e3b71c475910c085b96d41cb53 languageName: node linkType: hard @@ -2333,58 +2373,58 @@ __metadata: languageName: node linkType: hard -"turbo-darwin-64@npm:2.5.2": - version: 2.5.2 - resolution: "turbo-darwin-64@npm:2.5.2" +"turbo-darwin-64@npm:2.5.4": + version: 2.5.4 + resolution: "turbo-darwin-64@npm:2.5.4" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"turbo-darwin-arm64@npm:2.5.2": - version: 2.5.2 - resolution: "turbo-darwin-arm64@npm:2.5.2" +"turbo-darwin-arm64@npm:2.5.4": + version: 2.5.4 + resolution: "turbo-darwin-arm64@npm:2.5.4" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"turbo-linux-64@npm:2.5.2": - version: 2.5.2 - resolution: "turbo-linux-64@npm:2.5.2" +"turbo-linux-64@npm:2.5.4": + version: 2.5.4 + resolution: "turbo-linux-64@npm:2.5.4" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"turbo-linux-arm64@npm:2.5.2": - version: 2.5.2 - resolution: "turbo-linux-arm64@npm:2.5.2" +"turbo-linux-arm64@npm:2.5.4": + version: 2.5.4 + resolution: "turbo-linux-arm64@npm:2.5.4" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"turbo-windows-64@npm:2.5.2": - version: 2.5.2 - resolution: "turbo-windows-64@npm:2.5.2" +"turbo-windows-64@npm:2.5.4": + version: 2.5.4 + resolution: "turbo-windows-64@npm:2.5.4" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"turbo-windows-arm64@npm:2.5.2": - version: 2.5.2 - resolution: "turbo-windows-arm64@npm:2.5.2" +"turbo-windows-arm64@npm:2.5.4": + version: 2.5.4 + resolution: "turbo-windows-arm64@npm:2.5.4" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard "turbo@npm:^2.5.1": - version: 2.5.2 - resolution: "turbo@npm:2.5.2" - dependencies: - turbo-darwin-64: "npm:2.5.2" - turbo-darwin-arm64: "npm:2.5.2" - turbo-linux-64: "npm:2.5.2" - turbo-linux-arm64: "npm:2.5.2" - turbo-windows-64: "npm:2.5.2" - turbo-windows-arm64: "npm:2.5.2" + version: 2.5.4 + resolution: "turbo@npm:2.5.4" + dependencies: + turbo-darwin-64: "npm:2.5.4" + turbo-darwin-arm64: "npm:2.5.4" + turbo-linux-64: "npm:2.5.4" + turbo-linux-arm64: "npm:2.5.4" + turbo-windows-64: "npm:2.5.4" + turbo-windows-arm64: "npm:2.5.4" dependenciesMeta: turbo-darwin-64: optional: true @@ -2400,7 +2440,7 @@ __metadata: optional: true bin: turbo: bin/turbo - checksum: 10/dee9047dbeeddd5584744e604620267749e278e71f9658fd58ca72f6f71d38c47132ea958aee7b7049e51c85bcfce35ca6efb1e8d180b03d7504d7427f05b026 + checksum: 10/43dd952192a1261de3845ecac96d4f42ea6d8e49eaa4c339c029dbe010a1323957ef4b0080f8f06e3cd0169c1f00c356d32cbabde1ee08c72b0708f90994a774 languageName: node linkType: hard @@ -2463,41 +2503,41 @@ __metadata: languageName: node linkType: hard -"vite-node@npm:3.1.3": - version: 3.1.3 - resolution: "vite-node@npm:3.1.3" +"vite-node@npm:3.2.4": + version: 3.2.4 + resolution: "vite-node@npm:3.2.4" dependencies: cac: "npm:^6.7.14" - debug: "npm:^4.4.0" + debug: "npm:^4.4.1" es-module-lexer: "npm:^1.7.0" pathe: "npm:^2.0.3" - vite: "npm:^5.0.0 || ^6.0.0" + vite: "npm:^5.0.0 || ^6.0.0 || ^7.0.0-0" bin: vite-node: vite-node.mjs - checksum: 10/59c1e1397b055861390cf4e540ba1e968e4ad140df8e214f797dd73b9130f00855712779d4f6f0c8c5149bfe95db20ad55f349dd1962a143117a0d71d956235f + checksum: 10/343244ecabbab3b6e1a3065dabaeefa269965a7a7c54652d4b7a7207ee82185e887af97268c61755dcb2dd6a6ce5d9e114400cbd694229f38523e935703cc62f languageName: node linkType: hard -"vite@npm:^5.0.0 || ^6.0.0": - version: 6.3.5 - resolution: "vite@npm:6.3.5" +"vite@npm:^5.0.0 || ^6.0.0 || ^7.0.0-0": + version: 7.0.0-beta.2 + resolution: "vite@npm:7.0.0-beta.2" dependencies: esbuild: "npm:^0.25.0" - fdir: "npm:^6.4.4" + fdir: "npm:^6.4.6" fsevents: "npm:~2.3.3" picomatch: "npm:^4.0.2" - postcss: "npm:^8.5.3" - rollup: "npm:^4.34.9" - tinyglobby: "npm:^0.2.13" + postcss: "npm:^8.5.5" + rollup: "npm:^4.40.0" + tinyglobby: "npm:^0.2.14" peerDependencies: - "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + "@types/node": ^20.19.0 || >=22.12.0 jiti: ">=1.21.0" - less: "*" + less: ^4.0.0 lightningcss: ^1.21.0 - sass: "*" - sass-embedded: "*" - stylus: "*" - sugarss: "*" + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: ">=0.54.8" + sugarss: ^5.0.0 terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 @@ -2529,41 +2569,43 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10/7bc3a1c5ef79413ad70daeeaf69b76cd1218d16aa18ed8ee08d74648ef17284f4a17c11f5cf42b573b6dc5e3d5f115110b67b1d23c2c699cfe404757764a634a + checksum: 10/01245969939849d2a1fbfc6bba95b80079ecaf2a181bf530a35718bc8e093b49f92c0d228e64e7cf8d1976fdf77da5ca4ff0fd8d8e1df6bd81830c51c79e3b98 languageName: node linkType: hard "vitest@npm:^3.1.3": - version: 3.1.3 - resolution: "vitest@npm:3.1.3" - dependencies: - "@vitest/expect": "npm:3.1.3" - "@vitest/mocker": "npm:3.1.3" - "@vitest/pretty-format": "npm:^3.1.3" - "@vitest/runner": "npm:3.1.3" - "@vitest/snapshot": "npm:3.1.3" - "@vitest/spy": "npm:3.1.3" - "@vitest/utils": "npm:3.1.3" + version: 3.2.4 + resolution: "vitest@npm:3.2.4" + dependencies: + "@types/chai": "npm:^5.2.2" + "@vitest/expect": "npm:3.2.4" + "@vitest/mocker": "npm:3.2.4" + "@vitest/pretty-format": "npm:^3.2.4" + "@vitest/runner": "npm:3.2.4" + "@vitest/snapshot": "npm:3.2.4" + "@vitest/spy": "npm:3.2.4" + "@vitest/utils": "npm:3.2.4" chai: "npm:^5.2.0" - debug: "npm:^4.4.0" + debug: "npm:^4.4.1" expect-type: "npm:^1.2.1" magic-string: "npm:^0.30.17" pathe: "npm:^2.0.3" + picomatch: "npm:^4.0.2" std-env: "npm:^3.9.0" tinybench: "npm:^2.9.0" tinyexec: "npm:^0.3.2" - tinyglobby: "npm:^0.2.13" - tinypool: "npm:^1.0.2" + tinyglobby: "npm:^0.2.14" + tinypool: "npm:^1.1.1" tinyrainbow: "npm:^2.0.0" - vite: "npm:^5.0.0 || ^6.0.0" - vite-node: "npm:3.1.3" + vite: "npm:^5.0.0 || ^6.0.0 || ^7.0.0-0" + vite-node: "npm:3.2.4" why-is-node-running: "npm:^2.3.0" peerDependencies: "@edge-runtime/vm": "*" "@types/debug": ^4.1.12 "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 - "@vitest/browser": 3.1.3 - "@vitest/ui": 3.1.3 + "@vitest/browser": 3.2.4 + "@vitest/ui": 3.2.4 happy-dom: "*" jsdom: "*" peerDependenciesMeta: @@ -2583,7 +2625,7 @@ __metadata: optional: true bin: vitest: vitest.mjs - checksum: 10/ae74b401b15847615ec664260cf83eb2ce67c4bf018228bd0c48eae2e94309104a8a49b42ef422c27905e438d367207da15364d500f72cf2b723aff448c6a4e6 + checksum: 10/f10bbce093ecab310ecbe484536ef4496fb9151510b2be0c5907c65f6d31482d9c851f3182531d1d27d558054aa78e8efd9d4702ba6c82058657e8b6a52507ee languageName: node linkType: hard From abe386391debfc6c26ecbdf3eefa4c890d651037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 10:39:55 -0400 Subject: [PATCH 230/282] Move emptyString to Utils contract --- .../nonFungibleToken/src/NonFungibleToken.compact | 11 +---------- .../src/test/mocks/MockNonFungibleToken.compact | 4 ---- .../src/test/mocks/NonFungibleTokenTesting.compact | 11 +---------- .../src/test/nonFungibleToken.test.ts | 6 ------ .../src/test/simulators/NonFungibleTokenSimulator.ts | 10 ---------- contracts/utils/src/Utils.compact | 9 +++++++++ contracts/utils/src/test/mocks/MockUtils.compact | 12 ++++++++---- .../utils/src/test/simulators/UtilsSimulator.ts | 8 ++++++++ contracts/utils/src/test/utils.test.ts | 8 ++++++++ 9 files changed, 35 insertions(+), 44 deletions(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index 83711680..58c0b9eb 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -200,7 +200,7 @@ module NonFungibleToken { _requireOwned(tokenId); if (!_tokenURIs.member(tokenId)) { - return emptyString(); + return Utils_emptyString(); } return _tokenURIs.lookup(tokenId); @@ -763,13 +763,4 @@ module NonFungibleToken { return from; } - - /** - * @description A helper function that returns the empty string: "" - * - * @return {Opaque<"string">} - The empty string: "" - */ - pure circuit emptyString(): Opaque<"string"> { - return default>; - } } \ No newline at end of file diff --git a/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact index c782c1bd..af84bf9b 100644 --- a/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact @@ -162,8 +162,4 @@ export circuit _unsafeMint( tokenId: Uint<128> ): [] { return NonFungibleToken__unsafeMint(to, tokenId); -} - -export pure circuit emptyString(): Opaque<"string"> { - return NonFungibleToken_emptyString(); } \ No newline at end of file diff --git a/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact b/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact index c36730f6..618850c7 100644 --- a/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact +++ b/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact @@ -153,7 +153,7 @@ module NonFungibleTokenTesting { _requireOwned(tokenId); if (!_tokenURIs.member(tokenId)) { - return emptyString(); + return Utils_emptyString(); } return _tokenURIs.lookup(tokenId); @@ -676,13 +676,4 @@ module NonFungibleTokenTesting { return from; } - - /** - * @description A helper function that returns the empty string: "" - - * @return {Opaque<"string">} - The empty string: "" - */ - export pure circuit emptyString(): Opaque<"string"> { - return default>; - } } \ No newline at end of file diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index a2a03bcb..bd368164 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -1195,12 +1195,6 @@ describe('NonFungibleToken', () => { expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); }); - - describe('emptyString', () => { - it('should return the empty string', () => { - expect(token.emptyString()).toBe(''); - }); - }); }); type FailingCircuits = [ diff --git a/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts b/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts index c654eb92..e0b730a7 100644 --- a/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts +++ b/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts @@ -14,7 +14,6 @@ import { Contract as MockNonFungibleToken, type ZswapCoinPublicKey, ledger, - pureCircuits, } from '../../artifacts/MockNonFungibleToken/contract/index.cjs'; // Combined imports import { type NonFungibleTokenPrivateState, @@ -637,13 +636,4 @@ export class NonFungibleTokenSimulator tokenId, ).context; } - - /** - * @description A helper function that returns the empty string: "" - - * @return {Opaque<"string">} - The empty string: "" - */ - public emptyString(): '' { - return pureCircuits.emptyString() as ''; - } } diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index 21a04925..9995020c 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -67,4 +67,13 @@ module Utils { export pure circuit isContractAddress(keyOrAddress: Either): Boolean { return !keyOrAddress.is_left; } + + /** + * @description A helper function that returns the empty string: "" + * + * @return {Opaque<"string">} - The empty string: "" + */ + export pure circuit emptyString(): Opaque<"string"> { + return default>; + } } diff --git a/contracts/utils/src/test/mocks/MockUtils.compact b/contracts/utils/src/test/mocks/MockUtils.compact index 71ad1606..eaeb3d18 100644 --- a/contracts/utils/src/test/mocks/MockUtils.compact +++ b/contracts/utils/src/test/mocks/MockUtils.compact @@ -7,20 +7,24 @@ import "../../Utils" prefix Utils_; export { ZswapCoinPublicKey, ContractAddress, Either }; export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { - return Utils_isKeyOrAddressZero(keyOrAddress); + return Utils_isKeyOrAddressZero(keyOrAddress); } export pure circuit isKeyOrAddressEqual( keyOrAddress: Either, other: Either ): Boolean { - return Utils_isKeyOrAddressEqual(keyOrAddress, other); + return Utils_isKeyOrAddressEqual(keyOrAddress, other); } export pure circuit isKeyZero(key: ZswapCoinPublicKey): Boolean { - return Utils_isKeyZero(key); + return Utils_isKeyZero(key); } export pure circuit isContractAddress(keyOrAddress: Either): Boolean { - return Utils_isContractAddress(keyOrAddress); + return Utils_isContractAddress(keyOrAddress); +} + +export pure circuit emptyString(): Opaque<"string"> { + return Utils_emptyString(); } diff --git a/contracts/utils/src/test/simulators/UtilsSimulator.ts b/contracts/utils/src/test/simulators/UtilsSimulator.ts index 5b204e2d..4a607c7a 100644 --- a/contracts/utils/src/test/simulators/UtilsSimulator.ts +++ b/contracts/utils/src/test/simulators/UtilsSimulator.ts @@ -138,4 +138,12 @@ export class UtilsSimulator keyOrAddress, ).result; } + + /** + * @description A helper function that returns the empty string: "" + * @returns The empty string: "" + */ + public emptyString(): string { + return this.contract.circuits.emptyString(this.circuitContext).result; + } } diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 532da32e..faca5b73 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -9,6 +9,8 @@ const SOME_CONTRACT = const OTHER_CONTRACT = contractUtils.createEitherTestContractAddress('OTHER_CONTRACT'); +const EMPTY_STRING = ''; + let contract: UtilsSimulator; describe('Utils', () => { @@ -90,4 +92,10 @@ describe('Utils', () => { expect(contract.isContractAddress(Z_SOME_KEY)).toBe(false); }); }); + + describe('emptyString', () => { + it('should return the empty string', () => { + expect(contract.emptyString()).toBe(EMPTY_STRING); + }); + }); }); From fafbd51b81a8f66810c5cd9a4d8ac813cc4cb85d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 10:42:17 -0400 Subject: [PATCH 231/282] Update yarn.lock --- yarn.lock | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/yarn.lock b/yarn.lock index 6aca94eb..f2293782 100644 --- a/yarn.lock +++ b/yarn.lock @@ -416,6 +416,19 @@ __metadata: languageName: unknown linkType: soft +"@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken": + version: 0.0.0-use.local + resolution: "@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken" + dependencies: + "@biomejs/biome": "npm:1.9.4" + "@openzeppelin-midnight/compact": "workspace:^" + "@types/node": "npm:^22.14.0" + ts-node: "npm:^10.9.2" + typescript: "npm:^5.2.2" + vitest: "npm:^3.1.3" + languageName: unknown + linkType: soft + "@openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" From 7fc45e1d75e9bd7c7511cd1bc599f834db1f727d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 10:44:29 -0400 Subject: [PATCH 232/282] Reorganize code --- .../src/NonFungibleToken.compact | 102 +++++++++--------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index 58c0b9eb..88bab4d9 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -46,7 +46,7 @@ module NonFungibleToken { /// Public state export sealed ledger _name: Opaque<"string">; export sealed ledger _symbol: Opaque<"string">; - + /** * @description Mapping from token IDs to their owner addresses. * @type {Uint<128>} tokenId - The unique identifier for a token. @@ -493,6 +493,56 @@ module NonFungibleToken { } } + /** + * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner + * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. + * + * @circuitInfo k=12, rows=2049 + * + * Requirements: + * - The contract must have been initialized. + * - If `auth` is non 0, then this function will check that `auth` is either the owner of the token, + * or approved to operate on the token (by the owner). + * + * @param {Either} to - The intended recipient of the token transfer + * @param {Uint<128>} tokenId - The token being transfered + * @param {Either} auth - An account authorized to transfer the token + * @return {Either} - Owner of the token before it was transfered + */ + circuit _update( + to: Either, + tokenId: Uint<128>, + auth: Either + ): Either { + Initializable_assertInitialized(); + const from = _ownerOf(tokenId); + + // Perform (optional) operator check + if (!Utils_isKeyOrAddressZero(auth)) { + _checkAuthorized(from, auth, tokenId); + } + + // Execute the update + if (!Utils_isKeyOrAddressZero(from)) { + // Clear approval. No need to re-authorize + _approve(burn_address(), tokenId, burn_address()); + const newBalance = _balances.lookup(from) - 1 as Uint<128>; + _balances.insert(from, newBalance); + } + + if (!Utils_isKeyOrAddressZero(to)) { + if (!_balances.member(to)) { + _balances.insert(to, 0); + } + const newBalance = _balances.lookup(to) + 1 as Uint<128>; + _balances.insert(to, newBalance); + } + + _owners.insert(tokenId, to); + + return from; + } + /** * @description Mints `tokenId` and transfers it to `to`. * @@ -713,54 +763,4 @@ module NonFungibleToken { assert !Utils_isKeyOrAddressZero(owner) "NonFungibleToken: Nonexistent Token"; return owner; } - - /** - * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner - * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. - * - * @circuitInfo k=12, rows=2049 - * - * Requirements: - * - The contract must have been initialized. - * - If `auth` is non 0, then this function will check that `auth` is either the owner of the token, - * or approved to operate on the token (by the owner). - * - * @param {Either} to - The intended recipient of the token transfer - * @param {Uint<128>} tokenId - The token being transfered - * @param {Either} auth - An account authorized to transfer the token - * @return {Either} - Owner of the token before it was transfered - */ - circuit _update( - to: Either, - tokenId: Uint<128>, - auth: Either - ): Either { - Initializable_assertInitialized(); - const from = _ownerOf(tokenId); - - // Perform (optional) operator check - if (!Utils_isKeyOrAddressZero(auth)) { - _checkAuthorized(from, auth, tokenId); - } - - // Execute the update - if (!Utils_isKeyOrAddressZero(from)) { - // Clear approval. No need to re-authorize - _approve(burn_address(), tokenId, burn_address()); - const newBalance = _balances.lookup(from) - 1 as Uint<128>; - _balances.insert(from, newBalance); - } - - if (!Utils_isKeyOrAddressZero(to)) { - if (!_balances.member(to)) { - _balances.insert(to, 0); - } - const newBalance = _balances.lookup(to) + 1 as Uint<128>; - _balances.insert(to, newBalance); - } - - _owners.insert(tokenId, to); - - return from; - } } \ No newline at end of file From a4fe4c002b0f1ef444dc20c626a218e5ef30cd53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:39:48 -0400 Subject: [PATCH 233/282] Update contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Fleming Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- .../src/test/mocks/NonFungibleTokenTesting.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact b/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact index 618850c7..a8ca7fbb 100644 --- a/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact +++ b/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact @@ -676,4 +676,4 @@ module NonFungibleTokenTesting { return from; } -} \ No newline at end of file +} From 856de2f2d9b4d33670d3a62fa8380bf86ec622e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:39:56 -0400 Subject: [PATCH 234/282] Update contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Fleming Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- .../src/test/mocks/MockNonFungibleToken.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact index af84bf9b..ff75aa7d 100644 --- a/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact @@ -162,4 +162,4 @@ export circuit _unsafeMint( tokenId: Uint<128> ): [] { return NonFungibleToken__unsafeMint(to, tokenId); -} \ No newline at end of file +} From 20f57cfcc4ff1b06f112d21fd9c8c5ad262df6d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 01:09:45 -0400 Subject: [PATCH 235/282] Adds CI Tests, Lints, Compile, Build (#113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> Co-authored-by: Andrew Fleming --- yarn.lock | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/yarn.lock b/yarn.lock index f2293782..49a15924 100644 --- a/yarn.lock +++ b/yarn.lock @@ -392,6 +392,7 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/compact@workspace:compact" dependencies: + "@types/node": "npm:22.14.0" "@types/node": "npm:22.14.0" chalk: "npm:^5.4.1" fast-check: "npm:^3.15.0" @@ -416,25 +417,13 @@ __metadata: languageName: unknown linkType: soft -"@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken": - version: 0.0.0-use.local - resolution: "@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken" - dependencies: - "@biomejs/biome": "npm:1.9.4" - "@openzeppelin-midnight/compact": "workspace:^" - "@types/node": "npm:^22.14.0" - ts-node: "npm:^10.9.2" - typescript: "npm:^5.2.2" - vitest: "npm:^3.1.3" - languageName: unknown - linkType: soft - "@openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" dependencies: "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:22.14.0" + "@types/node": "npm:22.14.0" ts-node: "npm:^10.9.2" typescript: "npm:^5.2.2" vitest: "npm:^3.1.3" @@ -658,13 +647,6 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:^1.0.0": - version: 1.0.8 - resolution: "@types/estree@npm:1.0.8" - checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099 - languageName: node - linkType: hard - "@types/node@npm:22.14.0": version: 22.14.0 resolution: "@types/node@npm:22.14.0" @@ -674,12 +656,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^22, @types/node@npm:^22.14.0": - version: 22.15.32 - resolution: "@types/node@npm:22.15.32" +"@types/node@npm:22.14.0": + version: 22.14.0 + resolution: "@types/node@npm:22.14.0" dependencies: undici-types: "npm:~6.21.0" - checksum: 10/10b4c106d0c512a1d35ec08142bd7fb5cf2e1df93fc5627b3c69dd843dec4be07a47f1fa7ede232ad84762d75a372ea35028b79ee1e753b6f2adecd0b2cb2f71 + checksum: 10/d0669a8a37a18532c886ccfa51eb3fe1e46088deb4d3d27ebcd5d7d68bd6343ad1c7a3fcb85164780a57629359c33a6c917ecff748ea232bceac7692acc96537 languageName: node linkType: hard @@ -2477,13 +2459,6 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~5.26.4": - version: 5.26.5 - resolution: "undici-types@npm:5.26.5" - checksum: 10/0097779d94bc0fd26f0418b3a05472410408877279141ded2bd449167be1aed7ea5b76f756562cb3586a07f251b90799bab22d9019ceba49c037c76445f7cddd - languageName: node - linkType: hard - "undici-types@npm:~6.21.0": version: 6.21.0 resolution: "undici-types@npm:6.21.0" From 5e1f6947a47f192a0229fed8b2f884692a039c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:50:35 -0400 Subject: [PATCH 236/282] update yarn.lock --- yarn.lock | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 49a15924..b6a8ade5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -417,6 +417,19 @@ __metadata: languageName: unknown linkType: soft +"@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken": + version: 0.0.0-use.local + resolution: "@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken" + dependencies: + "@biomejs/biome": "npm:1.9.4" + "@openzeppelin-midnight/compact": "workspace:^" + "@types/node": "npm:^22.14.0" + ts-node: "npm:^10.9.2" + typescript: "npm:^5.2.2" + vitest: "npm:^3.1.3" + languageName: unknown + linkType: soft + "@openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" @@ -647,6 +660,13 @@ __metadata: languageName: node linkType: hard +"@types/estree@npm:^1.0.0": + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099 + languageName: node + linkType: hard + "@types/node@npm:22.14.0": version: 22.14.0 resolution: "@types/node@npm:22.14.0" @@ -656,12 +676,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:22.14.0": - version: 22.14.0 - resolution: "@types/node@npm:22.14.0" +"@types/node@npm:^22, @types/node@npm:^22.14.0": + version: 22.15.32 + resolution: "@types/node@npm:22.15.32" dependencies: undici-types: "npm:~6.21.0" - checksum: 10/d0669a8a37a18532c886ccfa51eb3fe1e46088deb4d3d27ebcd5d7d68bd6343ad1c7a3fcb85164780a57629359c33a6c917ecff748ea232bceac7692acc96537 + checksum: 10/10b4c106d0c512a1d35ec08142bd7fb5cf2e1df93fc5627b3c69dd843dec4be07a47f1fa7ede232ad84762d75a372ea35028b79ee1e753b6f2adecd0b2cb2f71 languageName: node linkType: hard From 4348a50dc21ad69bae42dfd4ca17b7293d746dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 17:37:34 -0400 Subject: [PATCH 237/282] Update Compiler Install Script --- .github/workflows/contracts-test-suite.yml | 122 --------------------- .github/workflows/test.yml | 7 ++ 2 files changed, 7 insertions(+), 122 deletions(-) delete mode 100644 .github/workflows/contracts-test-suite.yml diff --git a/.github/workflows/contracts-test-suite.yml b/.github/workflows/contracts-test-suite.yml deleted file mode 100644 index 1c89fc30..00000000 --- a/.github/workflows/contracts-test-suite.yml +++ /dev/null @@ -1,122 +0,0 @@ -name: Compact Contracts Test Suite - -on: - push: - paths: - - 'contracts/**/*.compact' - - 'contracts/**/*.ts' - -env: - TURBO_TELEMETRY_DISABLED: 1 - -jobs: - run-suite: - name: Run Test Suite - runs-on: ubuntu-24.04 - timeout-minutes: 15 - - steps: - - name: Check out code - uses: actions/checkout@v4 - with: - fetch-depth: 2 # Recommended by turbo team - - - name: Setup Environment - uses: ./.github/actions/setup - - - name: Build compact package - shell: bash - run: | - cd compact - turbo build - cd .. - - - name: Validate build artifacts - shell: bash - run: | - REQUIRED_FILES=( - "compact/dist/runCompiler.js" - "compact/dist/runBuilder.js" - ) - for file in "${REQUIRED_FILES[@]}"; do - if [ ! -f "$file" ]; then - echo "::error::❌ Missing required file: $file" - exit 1 - fi - done - - - name: Install Compact compiler - id: setup - shell: bash - run: | - # Set version variables - COMPILER_VERSION="0.23.0" - LANGUAGE_VERSION="0.15.0" - - # Create directory for compiler - COMPACT_HOME="$HOME/compactc" - mkdir -p "$COMPACT_HOME" - cd "$COMPACT_HOME" - - echo "⬇️ Downloading Compact compiler..." - curl -L https://d3fazakqrumx6p.cloudfront.net/artifacts/compiler/compactc_${COMPILER_VERSION}/compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip -o compactc.zip - unzip compactc.zip - chmod +x compactc.bin zkir compactc - - # Set up environment variables - echo "COMPACT_HOME=$COMPACT_HOME" >> $GITHUB_ENV - echo "$COMPACT_HOME" >> $GITHUB_PATH - - # Verify installation - [ -f "$COMPACT_HOME/compactc" ] || { echo "::error::❌ Failed to install compiler - compactc not found"; exit 1; } - - # Test installation - "$COMPACT_HOME/compactc" --version - - - name: Check compiler version - run: | - EXPECTED_COMPILER_VERSION="0.23.0" - COMPILER_OUTPUT=$(compactc --version) - COMPILER_VERSION=$(echo "$COMPILER_OUTPUT" | grep -oP '\b0\.[0-9]+\.[0-9]+\b' | head -n 1) - if [ "$COMPILER_VERSION" != "$EXPECTED_COMPILER_VERSION" ]; then - errMsg="❌ Compiler version mismatch!%0AExpected: $EXPECTED_COMPILER_VERSION%0AGot: $COMPILER_VERSION" - echo "::error::$errMsg" - exit 1 - fi - echo "✅ Compiler version matches: $COMPILER_VERSION" - - - name: Check language version - run: | - EXPECTED_LANGUAGE_VERSION="0.15.0" - LANGUAGE_OUTPUT=$(compactc --language-version) - LANGUAGE_VERSION=$(echo "$LANGUAGE_OUTPUT" | grep -oP '\b0\.[0-9]+\.[0-9]+\b' | tail -n 1) - if [ "$LANGUAGE_VERSION" != "$EXPECTED_LANGUAGE_VERSION" ]; then - errMsg="❌ Language version mismatch!%0AExpected: $EXPECTED_LANGUAGE_VERSION%0AGot: $LANGUAGE_VERSION" - echo "::error::$errMsg" - exit 1 - fi - echo "✅ Language version matches: $LANGUAGE_VERSION" - - - name: Build contracts - run: turbo build --filter="./contracts/*" - timeout-minutes: 10 - - - name: Check if build artifacts exist - run: | - if ! find contracts -type d -name artifacts | grep -q . ; then - echo "::error::❌ Build artifacts not found in any contracts/*/artifacts" - exit 1 - fi - - # List build artifacts - echo "✅ Build artifacts found:" - echo "Package build artifacts (dist):" - find contracts -name "dist" -type d -exec ls -la {} \; - echo -e "\nCompact code artifacts (src/artifacts):" - find contracts -name "artifacts" -type d -exec ls -la {} \; - - - name: Run type checks - run: turbo types - - - name: Run Contract Tests - run: turbo test \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d8f64297..e6a50dc4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,6 +10,7 @@ env: TURBO_TELEMETRY_DISABLED: 1 COMPILER_VERSION: "0.23.0" LANGUAGE_VERSION: "0.15.0" + MIDNIGHT_CACHE_PATH: "/home/runner/.cache/midnight/zk-params/bls_filecoin_2p11" jobs: run-suite: @@ -34,6 +35,12 @@ jobs: # Create directory for compiler COMPACT_HOME="$HOME/compactc" mkdir -p "$COMPACT_HOME" + if [ -f $MIDNIGHT_CACHE_PATH ]; then + echo "$MIDNIGHT_CACHE_PATH exists with hash $(sha256sum "$MIDNIGHT_CACHE_PATH" | awk '${print $1}')" + else + echo "File does not exist." + exit 1; + fi # Create URL ZIP_FILE="compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip" From f9cc45bd6230a93350e22494dc6f11d129616b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:50:35 -0400 Subject: [PATCH 238/282] update yarn.lock Update Compiler Install Script Revert "update yarn.lock" This reverts commit ddc0a94a74b8b7314a3e4936be7e8b6dc54f5364. Revert "Update Compiler Install Script" This reverts commit f218badbaf16eb3876a4936623b202166e8a1e89. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e6a50dc4..90d7c076 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -88,4 +88,4 @@ jobs: echo "✅ Language version matches: $COMPUTED_LANGUAGE_VERSION" - name: Compile, test, and check types - run: turbo compact types test + run: turbo compact -- --ski-zk && turbo types test From 17ac85e8a03805e9c42ac7b5eec5c90e3ad67ea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 18:16:20 -0400 Subject: [PATCH 239/282] Update CI workflow --- .github/workflows/test.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 90d7c076..1cb67804 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,6 @@ env: TURBO_TELEMETRY_DISABLED: 1 COMPILER_VERSION: "0.23.0" LANGUAGE_VERSION: "0.15.0" - MIDNIGHT_CACHE_PATH: "/home/runner/.cache/midnight/zk-params/bls_filecoin_2p11" jobs: run-suite: @@ -35,12 +34,6 @@ jobs: # Create directory for compiler COMPACT_HOME="$HOME/compactc" mkdir -p "$COMPACT_HOME" - if [ -f $MIDNIGHT_CACHE_PATH ]; then - echo "$MIDNIGHT_CACHE_PATH exists with hash $(sha256sum "$MIDNIGHT_CACHE_PATH" | awk '${print $1}')" - else - echo "File does not exist." - exit 1; - fi # Create URL ZIP_FILE="compactc_v${COMPILER_VERSION}_x86_64-unknown-linux-musl.zip" @@ -88,4 +81,4 @@ jobs: echo "✅ Language version matches: $COMPUTED_LANGUAGE_VERSION" - name: Compile, test, and check types - run: turbo compact -- --ski-zk && turbo types test + run: turbo compact -- --skip-zk && turbo types test From 9a7eab68a0e722a41968e9f0464d8ab3ae8d5694 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Mon, 23 Jun 2025 12:46:14 -0300 Subject: [PATCH 240/282] Fix `Hash mismatch` error in CI (#148) --- .github/workflows/test.yml | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1cb67804..52399e2d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -80,5 +80,32 @@ jobs: echo "✅ Language version matches: $COMPUTED_LANGUAGE_VERSION" - - name: Compile, test, and check types - run: turbo compact -- --skip-zk && turbo types test + - name: Compile contracts (with retry on hash mismatch) + shell: bash + run: | + set -euo pipefail + + compile() { + echo "⚙️ Running Compact compilation..." + if ! output=$(turbo compact --concurrency=1 2>&1); then + echo "❌ Compilation failed." + + if echo "$output" | grep -q "Hash mismatch" && [ -d "$HOME/.cache/midnight/zk-params" ]; then + echo "⚠️ Hash mismatch detected *and* zk-params exists. Removing cache..." + rm -rf "$HOME/.cache/midnight/zk-params" + echo "::notice::♻️ Retrying compilation after clearing zk-params..." + turbo compact --concurrency=1 || { echo "::error::❌ Retry also failed."; exit 1; } + else + echo "🚫 Compilation failed for another reason or zk-params missing. No retry." + exit 1 + fi + fi + } + + compile + + - name: Run type checks + run: turbo types + + - name: Run tests + run: turbo test From 657d34b08d8752318a1b904280c9b992178ccca5 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Mon, 23 Jun 2025 16:39:08 -0500 Subject: [PATCH 241/282] Fix fmt issue (#143) --- biome.json | 3 ++- compact/package.json | 5 ++++- package.json | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/biome.json b/biome.json index 2905c7ef..5e4b9777 100644 --- a/biome.json +++ b/biome.json @@ -20,7 +20,8 @@ }, "formatter": { "enabled": true, - "indentStyle": "space" + "indentStyle": "space", + "ignore": ["package.json"] }, "organizeImports": { "enabled": true diff --git a/compact/package.json b/compact/package.json index dca0a1dd..8e4541ed 100644 --- a/compact/package.json +++ b/compact/package.json @@ -3,7 +3,10 @@ "name": "@openzeppelin-midnight/compact", "private": true, "version": "0.0.1", - "keywords": ["compact", "compiler"], + "keywords": [ + "compact", + "compiler" + ], "author": "", "license": "MIT", "description": "Compact fetcher", diff --git a/package.json b/package.json index c27e082a..3fe48c95 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,11 @@ "description": "Secure Smart Contract library for Midnight", "private": true, "packageManager": "yarn@4.1.0", - "workspaces": ["compact/", "contracts/*/", "docs/"], + "workspaces": [ + "compact/", + "contracts/*/", + "docs/" + ], "scripts": { "docs": "npx turbo run docs --filter=docs", "docs:watch": "npx turbo run docs:watch --filter=docs", From 72f50374ae737689770367c1d8141ed0113e9362 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 24 Jun 2025 22:55:39 -0500 Subject: [PATCH 242/282] Update fungible token (#125) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andrew Fleming Co-authored-by: Iskander Co-authored-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- README.md | 12 +- contracts/fungibleToken/package.json | 32 + .../fungibleToken/src/FungibleToken.compact | 565 ++++++++++++ .../src/test/FungibleToken.test.ts | 846 ++++++++++++++++++ .../src/test/mocks/MockFungibleToken.compact | 135 +++ .../test/simulators/FungibleTokenSimulator.ts | 434 +++++++++ .../fungibleToken/src/test/types/string.ts | 4 + .../fungibleToken/src/test/types/test.ts | 26 + .../fungibleToken/src/test/utils/address.ts | 77 ++ .../fungibleToken/src/test/utils/test.ts | 68 ++ .../src/witnesses/FungibleTokenWitnesses.ts | 3 + contracts/fungibleToken/tsconfig.build.json | 5 + contracts/fungibleToken/tsconfig.json | 21 + contracts/{erc20 => fungibleToken}/turbo.json | 0 contracts/fungibleToken/vitest.config.ts | 10 + contracts/utils/src/Utils.compact | 9 +- .../utils/src/test/mocks/MockUtils.compact | 15 + contracts/utils/src/test/utils.test.ts | 51 ++ docs/modules/ROOT/pages/index.adoc | 12 +- yarn.lock | 21 +- 20 files changed, 2315 insertions(+), 31 deletions(-) create mode 100644 contracts/fungibleToken/package.json create mode 100644 contracts/fungibleToken/src/FungibleToken.compact create mode 100644 contracts/fungibleToken/src/test/FungibleToken.test.ts create mode 100644 contracts/fungibleToken/src/test/mocks/MockFungibleToken.compact create mode 100644 contracts/fungibleToken/src/test/simulators/FungibleTokenSimulator.ts create mode 100644 contracts/fungibleToken/src/test/types/string.ts create mode 100644 contracts/fungibleToken/src/test/types/test.ts create mode 100644 contracts/fungibleToken/src/test/utils/address.ts create mode 100644 contracts/fungibleToken/src/test/utils/test.ts create mode 100644 contracts/fungibleToken/src/witnesses/FungibleTokenWitnesses.ts create mode 100644 contracts/fungibleToken/tsconfig.build.json create mode 100644 contracts/fungibleToken/tsconfig.json rename contracts/{erc20 => fungibleToken}/turbo.json (100%) create mode 100644 contracts/fungibleToken/vitest.config.ts diff --git a/README.md b/README.md index fff600b6..ec3108b3 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,9 @@ turbo compact $ turbo compact (...) -✔ [COMPILE] [1/2] Compiled ERC20.compact -@openzeppelin-midnight/erc20:compact: Compactc version: 0.23.0 -@openzeppelin-midnight/erc20:compact: +✔ [COMPILE] [1/2] Compiled FungibleToken.compact +@openzeppelin-midnight/fungible-token:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/fungible-token:compact: ✔ [COMPILE] [1/6] Compiled Initializable.compact @openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 @openzeppelin-midnight/utils:compact: @@ -75,9 +75,9 @@ $ turbo compact @openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 @openzeppelin-midnight/utils:compact: -✔ [COMPILE] [2/2] Compiled test/mocks/MockERC20.compact -@openzeppelin-midnight/erc20:compact: Compactc version: 0.23.0 -@openzeppelin-midnight/erc20:compact: Compiling 15 circuits: +✔ [COMPILE] [2/2] Compiled test/mocks/MockFungibleToken.compact +@openzeppelin-midnight/fungible-token:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/fungible-token:compact: Compiling 15 circuits: Tasks: 2 successful, 2 total diff --git a/contracts/fungibleToken/package.json b/contracts/fungibleToken/package.json new file mode 100644 index 00000000..68b33631 --- /dev/null +++ b/contracts/fungibleToken/package.json @@ -0,0 +1,32 @@ +{ + "name": "@openzeppelin-midnight/fungible-token", + "private": true, + "type": "module", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "scripts": { + "compact": "compact-compiler", + "build": "compact-builder && tsc", + "test": "vitest run", + "types": "tsc -p tsconfig.json --noEmit", + "clean": "git clean -fXd" + }, + "dependencies": { + "@openzeppelin-midnight/compact": "workspace:^" + }, + "devDependencies": { + "@types/node": "22.14.0", + "ts-node": "^10.9.2", + "typescript": "^5.2.2", + "vitest": "^3.1.3" + } +} diff --git a/contracts/fungibleToken/src/FungibleToken.compact b/contracts/fungibleToken/src/FungibleToken.compact new file mode 100644 index 00000000..7c53ad02 --- /dev/null +++ b/contracts/fungibleToken/src/FungibleToken.compact @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.15.0; + +/** + * @module FungibleToken + * @description An unshielded FungibleToken library. + * + * @notice One notable difference regarding this implementation and the EIP20 spec + * consists of the token size. Uint<128> is used as the token size because Uint<256> + * cannot be supported. + * This is due to encoding limits on the midnight circuit backend: + * https://github.com/midnightntwrk/compactc/issues/929 + * + * @notice At the moment Midnight does not support contract-to-contract communication, but + * there are ongoing efforts to enable this in the future. Thus, the main circuits of this module + * restrict developers from sending tokens to contracts; however, we provide developers + * the ability to experiment with sending tokens to contracts using the `_unsafe` + * transfer methods. Once contract-to-contract communication is available we will follow the + * deprecation plan outlined below: + * + * Initial Minor Version Change: + * + * - Mark _unsafeFN as deprecated and emit a warning if possible. + * - Keep its implementation intact so existing callers continue to work. + * + * Later Major Version Change: + * + * - Drop _unsafeFN and remove `isContract` guard from `FN`. + * - By this point, anyone using _unsafeFN should have migrated to the now C2C-capable `FN`. + * + * Due to the vast incompatibilities with the EIP20 spec, it is our + * opinion that this implementation should not be called ERC20 at this time + * as this would be both very confusing and misleading. This may change as more + * features become available. The list of missing features is as follows: + * + * - Full uint256 support. + * - Events. + * - Contract-to-contract calls. + */ +module FungibleToken { + import CompactStandardLibrary; + import "../../node_modules/@openzeppelin-midnight/utils/src/Initializable" prefix Initializable_; + import "../../node_modules/@openzeppelin-midnight/utils/src/Utils" prefix Utils_; + + /** + * @description Mapping from account addresses to their token balances. + * @type {Either} account - The account address. + * @type {Uint<128>} balance - The balance of the account. + * @type {Map} + * @type {Map, Uint<128>>} _balances + */ + export ledger _balances: Map, Uint<128>>; + /** + * @description Mapping from owner accounts to spender accounts and their allowances. + * @type {Either} account - The owner account address. + * @type {Either} spender - The spender account address. + * @type {Uint<128>} allowance - The amount allowed to be spent by the spender. + * @type {Map>} + * @type {Map, Map, Uint<128>>>} _allowances + */ + export ledger _allowances: Map, Map, Uint<128>>>; + + export ledger _totalSupply: Uint<128>; + + export sealed ledger _name: Opaque<"string">; + export sealed ledger _symbol: Opaque<"string">; + export sealed ledger _decimals: Uint<8>; + + /** + * @description Initializes the contract by setting the name, symbol, and decimals. + * @dev This MUST be called in the implementing contract's constructor. Failure to do so + * can lead to an irreparable contract. + * + * @param {Opaque<"string">} name_ - The name of the token. + * @param {Opaque<"string">} symbol_ - The symbol of the token. + * @param {Uint<8>} decimals_ - The number of decimals used to get the user representation. + * @return {[]} - None. + */ + export circuit initialize( + name_: Opaque<"string">, + symbol_: Opaque<"string">, + decimals_:Uint<8> + ): [] { + Initializable_initialize(); + _name = name_; + _symbol = symbol_; + _decimals = decimals_; + } + + /** + * @description Returns the token name. + * + * Requirements: + * + * - Contract is initialized. + * + * @return {Opaque<"string">} - The token name. + */ + export circuit name(): Opaque<"string"> { + Initializable_assertInitialized(); + return _name; + } + + /** + * @description Returns the symbol of the token. + * + * Requirements: + * + * - Contract is initialized. + * + * @return {Opaque<"string">} - The token name. + */ + export circuit symbol(): Opaque<"string"> { + Initializable_assertInitialized(); + return _symbol; + } + + /** + * @description Returns the number of decimals used to get its user representation. + * + * Requirements: + * + * - Contract is initialized. + * + * @return {Uint<8>} - The account's token balance. + */ + export circuit decimals(): Uint<8> { + Initializable_assertInitialized(); + return _decimals; + } + + /** + * @description Returns the value of tokens in existence. + * + * Requirements: + * + * - Contract is initialized. + * + * @return {Uint<128>} - The total supply of tokens. + */ + export circuit totalSupply(): Uint<128> { + Initializable_assertInitialized(); + return _totalSupply; + } + + /** + * @description Returns the value of tokens owned by `account`. + * + * @dev Manually checks if `account` is a key in the map and returns 0 if it is not. + * + * Requirements: + * + * - Contract is initialized. + * + * @param {Either} account - The public key or contract address to query. + * @return {Uint<128>} - The account's token balance. + */ + export circuit balanceOf(account: Either): Uint<128> { + Initializable_assertInitialized(); + if (!_balances.member(account)) { + return 0; + } + + return _balances.lookup(account); + } + + /** + * @description Moves a `value` amount of tokens from the caller's account to `to`. + * + * @notice Transfers to contract addresses are currently disallowed until contract-to-contract + * interactions are supported in Compact. This restriction prevents assets from + * being inadvertently locked in contracts that cannot currently handle token receipt. + * + * Requirements: + * + * - Contract is initialized. + * - `to` is not a ContractAddress. + * - `to` is not the zero address. + * - The caller has a balance of at least `value`. + * + * @param {Either} to - The recipient of the transfer, either a user or a contract. + * @param {Uint<128>} value - The amount to transfer. + * @return {Boolean} - As per the IERC20 spec, this MUST return true. + */ + export circuit transfer(to: Either, value: Uint<128>): Boolean { + Initializable_assertInitialized(); + assert !Utils_isContractAddress(to) "FungibleToken: Unsafe Transfer"; + return _unsafeTransfer(to, value); + } + + /** + * @description Unsafe variant of `transfer` which allows transfers to contract addresses. + * + * @warning Transfers to contract addresses are considered unsafe because contract-to-contract + * calls are not currently supported. Tokens sent to a contract address may become irretrievable. + * Once contract-to-contract calls are supported, this circuit may be deprecated. + * + * Requirements: + * + * - Contract is initialized. + * - `to` is not the zero address. + * - The caller has a balance of at least `value`. + * + * @param {Either} to - The recipient of the transfer, either a user or a contract. + * @param {Uint<128>} value - The amount to transfer. + * @return {Boolean} - As per the IERC20 spec, this MUST return true. + */ + export circuit _unsafeTransfer(to: Either, value: Uint<128>): Boolean { + Initializable_assertInitialized(); + const owner = left(own_public_key()); + _unsafeUncheckedTransfer(owner, to, value); + return true; + } + + /** + * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` + * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. + * + * @dev Manually checks if `owner` and `spender` are keys in the map and returns 0 if they are not. + * + * Requirements: + * + * - Contract is initialized. + * + * @param {Either} owner - The public key or contract address of approver. + * @param {Either} spender - The public key or contract address of spender. + * @return {Uint<128>} - The `spender`'s allowance over `owner`'s tokens. + */ + export circuit allowance( + owner: Either, + spender: Either + ): Uint<128> { + Initializable_assertInitialized(); + if (!_allowances.member(owner) || !_allowances.lookup(owner).member(spender)) { + return 0; + } + + return _allowances.lookup(owner).lookup(spender); + } + + /** + * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. + * + * Requirements: + * + * - Contract is initialized. + * - `spender` is not the zero address. + * + * @param {Either} spender - The Zswap key or ContractAddress that may spend on behalf of the caller. + * @param {Uint<128>} value - The amount of tokens the `spender` may spend. + * @return {Boolean} - Returns a boolean value indicating whether the operation succeeded. + */ + export circuit approve(spender: Either, value: Uint<128>): Boolean { + Initializable_assertInitialized(); + + const owner = left(own_public_key()); + _approve(owner, spender, value); + return true; + } + + /** + * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. + * `value` is the deducted from the caller's allowance. + * + * @notice Transfers to contract addresses are currently disallowed until contract-to-contract + * interactions are supported in Compact. This restriction prevents assets from + * being inadvertently locked in contracts that cannot currently handle token receipt. + * + * Requirements: + * + * - Contract is initialized. + * - `from` is not the zero address. + * - `from` must have a balance of at least `value`. + * - `to` is not the zero address. + * - `to` is not a ContractAddress. + * - The caller has an allowance of `from`'s tokens of at least `value`. + * + * @param {Either} from - The current owner of the tokens for the transfer, either a user or a contract. + * @param {Either} to - The recipient of the transfer, either a user or a contract. + * @param {Uint<128>} value - The amount to transfer. + * @return {Boolean} - As per the IERC20 spec, this MUST return true. + */ + export circuit transferFrom( + from: Either, + to: Either, + value: Uint<128> + ): Boolean { + Initializable_assertInitialized(); + assert !Utils_isContractAddress(to) "FungibleToken: Unsafe Transfer"; + return _unsafeTransferFrom(from, to, value); + } + + /** + * @description Unsafe variant of `transferFrom` which allows transfers to contract addresses. + * + * @warning Transfers to contract addresses are considered unsafe because contract-to-contract + * calls are not currently supported. Tokens sent to a contract address may become irretrievable. + * Once contract-to-contract calls are supported, this circuit may be deprecated. + * + * Requirements: + * + * - Contract is initialized. + * - `from` is not the zero address. + * - `from` must have a balance of at least `value`. + * - `to` is not the zero address. + * - The caller has an allowance of `from`'s tokens of at least `value`. + * + * @param {Either} from - The current owner of the tokens for the transfer, either a user or a contract. + * @param {Either} to - The recipient of the transfer, either a user or a contract. + * @param {Uint<128>} value - The amount to transfer. + * @return {Boolean} - As per the IERC20 spec, this MUST return true. + */ + export circuit _unsafeTransferFrom( + from: Either, + to: Either, + value: Uint<128> + ): Boolean { + Initializable_assertInitialized(); + + const spender = left(own_public_key()); + _spendAllowance(from, spender, value); + _unsafeUncheckedTransfer(from, to, value); + return true; + } + + /** + * @description Moves a `value` amount of tokens from `from` to `to`. + * This circuit is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * @notice Transfers to contract addresses are currently disallowed until contract-to-contract + * interactions are supported in Compact. This restriction prevents assets from + * being inadvertently locked in contracts that cannot currently handle token receipt. + * + * Requirements: + * + * - Contract is initialized. + * - `from` is not be the zero address. + * - `from` must have at least a balance of `value`. + * - `to` must not be the zero address. + * - `to` must not be a ContractAddress. + * + * @param {Either} from - The owner of the tokens to transfer. + * @param {Either} to - The receipient of the transferred tokens. + * @param {Uint<128>} value - The amount of tokens to transfer. + * @return {[]} - None. + */ + export circuit _transfer( + from: Either, + to: Either, + value: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isContractAddress(to) "FungibleToken: Unsafe Transfer"; + _unsafeUncheckedTransfer(from, to, value); + } + + /** + * @description Unsafe variant of `transferFrom` which allows transfers to contract addresses. + * + * @warning Transfers to contract addresses are considered unsafe because contract-to-contract + * calls are not currently supported. Tokens sent to a contract address may become irretrievable. + * Once contract-to-contract calls are supported, this circuit may be deprecated. + * + * Requirements: + * + * - Contract is initialized. + * - `from` is not the zero address. + * - `to` is not the zero address. + * + * @param {Either} from - The owner of the tokens to transfer. + * @param {Either} to - The receipient of the transferred tokens. + * @param {Uint<128>} value - The amount of tokens to transfer. + * @return {[]} - None. + */ + export circuit _unsafeUncheckedTransfer( + from: Either, + to: Either, + value: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isKeyOrAddressZero(from) "FungibleToken: invalid sender"; + assert !Utils_isKeyOrAddressZero(to) "FungibleToken: invalid receiver"; + + _update(from, to, value); + } + + /** + * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` + * (or `to`) is the zero address. + * @dev Checks for a mint overflow in order to output a more readable error message. + * + * Requirements: + * + * - Contract is initialized. + * + * @param {Either} from - The original owner of the tokens moved (which is 0 if tokens are minted). + * @param {Either} to - The recipient of the tokens moved (which is 0 if tokens are burned). + * @param {Uint<128>} value - The amount of tokens moved from `from` to `to`. + * @return {[]} - None. + */ + circuit _update( + from: Either, + to: Either, + value: Uint<128> + ): [] { + Initializable_assertInitialized(); + if (Utils_isKeyOrAddressZero(from)) { + // Mint + const MAX_UINT128 = 340282366920938463463374607431768211455; + assert MAX_UINT128 - _totalSupply >= value "FungibleToken: arithmetic overflow"; + + _totalSupply = _totalSupply + value as Uint<128>; + } else { + const fromBal = balanceOf(from); + assert fromBal >= value "FungibleToken: insufficient balance"; + _balances.insert(from, fromBal - value as Uint<128>); + } + + if (Utils_isKeyOrAddressZero(to)) { + // Burn + _totalSupply = _totalSupply - value as Uint<128>; + } else { + const toBal = balanceOf(to); + _balances.insert(to, toBal + value as Uint<128>); + } + } + + /** + * @description Creates a `value` amount of tokens and assigns them to `account`, + * by transferring it from the zero address. Relies on the `update` mechanism. + * + * @notice Transfers to contract addresses are currently disallowed until contract-to-contract + * interactions are supported in Compact. This restriction prevents assets from + * being inadvertently locked in contracts that cannot currently handle token receipt. + * + * Requirements: + * + * - Contract is initialized. + * - `to` is not a ContractAddress. + * - `account` is not the zero address. + * + * @param {Either} account - The recipient of tokens minted. + * @param {Uint<128>} value - The amount of tokens minted. + * @return {[]} - None. + */ + export circuit _mint( + account: Either, + value: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isContractAddress(account) "FungibleToken: Unsafe Transfer"; + _unsafeMint(account, value); + } + + /** + * @description Unsafe variant of `_mint` which allows transfers to contract addresses. + * + * @warning Transfers to contract addresses are considered unsafe because contract-to-contract + * calls are not currently supported. Tokens sent to a contract address may become irretrievable. + * Once contract-to-contract calls are supported, this circuit may be deprecated. + * + * Requirements: + * + * - Contract is initialized. + * - `account` is not the zero address. + * + * @param {Either} account - The recipient of tokens minted. + * @param {Uint<128>} value - The amount of tokens minted. + * @return {[]} - None. + */ + export circuit _unsafeMint( + account: Either, + value: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isKeyOrAddressZero(account) "FungibleToken: invalid receiver"; + _update(burn_address(), account, value); + } + + /** + * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. + * Relies on the `_update` mechanism. + * + * Requirements: + * + * - Contract is initialized. + * - `account` is not the zero address. + * - `account` must have at least a balance of `value`. + * + * @param {Either} account - The target owner of tokens to burn. + * @param {Uint<128>} value - The amount of tokens to burn. + * @return {[]} - None. + */ + export circuit _burn( + account: Either, + value: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isKeyOrAddressZero(account) "FungibleToken: invalid sender"; + _update(account, burn_address(), value); + } + + /** + * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. + * This circuit is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Requirements: + * + * - Contract is initialized. + * - `owner` is not the zero address. + * - `spender` is not the zero address. + * + * @param {Either} owner - The owner of the tokens. + * @param {Either} spender - The spender of the tokens. + * @param {Uint<128>} value - The amount of tokens `spender` may spend on behalf of `owner`. + * @return {[]} - None. + */ + export circuit _approve( + owner: Either, + spender: Either, + value: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert !Utils_isKeyOrAddressZero(owner) "FungibleToken: invalid owner"; + assert !Utils_isKeyOrAddressZero(spender) "FungibleToken: invalid spender"; + if (!_allowances.member(owner)) { + // If owner doesn't exist, create and insert a new sub-map directly + _allowances.insert(owner, default, Uint<128>>>); + } + _allowances.lookup(owner).insert(spender, value); + } + + /** + * @description Updates `owner`'s allowance for `spender` based on spent `value`. + * Does not update the allowance value in case of infinite allowance. + * + * Requirements: + * + * - Contract is initialized. + * - `spender` must have at least an allowance of `value` from `owner`. + * + * @param {Either} owner - The owner of the tokens. + * @param {Either} spender - The spender of the tokens. + * @param {Uint<128>} value - The amount of token allowance to spend. + * @return {[]} - None. + */ + export circuit _spendAllowance( + owner: Either, + spender: Either, + value: Uint<128> + ): [] { + Initializable_assertInitialized(); + assert (_allowances.member(owner) && _allowances.lookup(owner).member(spender)) "FungibleToken: insufficient allowance"; + + const currentAllowance = _allowances.lookup(owner).lookup(spender); + const MAX_UINT128 = 340282366920938463463374607431768211455; + if (currentAllowance < MAX_UINT128) { + assert currentAllowance >= value "FungibleToken: insufficient allowance"; + _approve(owner, spender, currentAllowance - value as Uint<128>); + } + } +} diff --git a/contracts/fungibleToken/src/test/FungibleToken.test.ts b/contracts/fungibleToken/src/test/FungibleToken.test.ts new file mode 100644 index 00000000..3939491c --- /dev/null +++ b/contracts/fungibleToken/src/test/FungibleToken.test.ts @@ -0,0 +1,846 @@ +import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { FungibleTokenSimulator } from './simulators/FungibleTokenSimulator'; +import * as utils from './utils/address'; + +// Metadata +const EMPTY_STRING = ''; +const NAME = 'NAME'; +const SYMBOL = 'SYMBOL'; +const DECIMALS = 18n; +const NO_DECIMALS = 0n; +const INIT = true; +const BAD_INIT = false; + +// Amounts +const AMOUNT: bigint = BigInt(250); +const MAX_UINT128 = BigInt(2 ** 128) - BigInt(1); + +// Callers +const OWNER = utils.toHexPadded('OWNER'); +const SPENDER = utils.toHexPadded('SPENDER'); +const UNAUTHORIZED = utils.toHexPadded('UNAUTHORIZED'); +const ZERO = utils.toHexPadded(''); + +// Encoded PK/Addresses +const Z_OWNER = utils.createEitherTestUser('OWNER'); +const Z_RECIPIENT = utils.createEitherTestUser('RECIPIENT'); +const Z_SPENDER = utils.createEitherTestUser('SPENDER'); +const Z_OTHER = utils.createEitherTestUser('OTHER'); +const Z_OWNER_CONTRACT = + utils.createEitherTestContractAddress('OWNER_CONTRACT'); +const Z_RECIPIENT_CONTRACT = + utils.createEitherTestContractAddress('RECIPIENT_CONTRACT'); + +// Helper types +const ownerTypes = [ + ['contract', Z_OWNER_CONTRACT], + ['pubkey', Z_OWNER], +] as const; + +const recipientTypes = [ + ['contract', Z_RECIPIENT_CONTRACT], + ['pubkey', Z_RECIPIENT], +] as const; + +let token: FungibleTokenSimulator; +let caller: CoinPublicKey; + +describe('FungibleToken', () => { + describe('before initialization', () => { + it('should initialize metadata', () => { + token = new FungibleTokenSimulator(NAME, SYMBOL, DECIMALS, INIT); + + expect(token.name()).toEqual(NAME); + expect(token.symbol()).toEqual(SYMBOL); + expect(token.decimals()).toEqual(DECIMALS); + }); + + it('should initialize empty metadata', () => { + token = new FungibleTokenSimulator( + EMPTY_STRING, + EMPTY_STRING, + NO_DECIMALS, + INIT, + ); + + expect(token.name()).toEqual(EMPTY_STRING); + expect(token.symbol()).toEqual(EMPTY_STRING); + expect(token.decimals()).toEqual(NO_DECIMALS); + }); + }); + + describe('when not initialized correctly', () => { + beforeEach(() => { + token = new FungibleTokenSimulator( + EMPTY_STRING, + EMPTY_STRING, + NO_DECIMALS, + BAD_INIT, + ); + }); + + type FailingCircuits = [ + method: keyof FungibleTokenSimulator, + args: unknown[], + ]; + // Circuit calls should fail before the args are used + const circuitsToFail: FailingCircuits[] = [ + ['name', []], + ['symbol', []], + ['decimals', []], + ['totalSupply', []], + ['balanceOf', [Z_OWNER]], + ['allowance', [Z_OWNER, Z_SPENDER]], + ['transfer', [Z_RECIPIENT, AMOUNT]], + ['_unsafeTransfer', [Z_RECIPIENT, AMOUNT]], + ['transferFrom', [Z_OWNER, Z_RECIPIENT, AMOUNT]], + ['_unsafeTransferFrom', [Z_OWNER, Z_RECIPIENT, AMOUNT]], + ['approve', [Z_OWNER, AMOUNT]], + ['_approve', [Z_OWNER, Z_SPENDER, AMOUNT]], + ['_transfer', [Z_OWNER, Z_RECIPIENT, AMOUNT]], + ['_unsafeUncheckedTransfer', [Z_OWNER, Z_RECIPIENT, AMOUNT]], + ['_mint', [Z_OWNER, AMOUNT]], + ['_unsafeMint', [Z_OWNER, AMOUNT]], + ['_burn', [Z_OWNER, AMOUNT]], + ]; + + it.each(circuitsToFail)('%s should fail', (circuitName, args) => { + expect(() => { + (token[circuitName] as (...args: unknown[]) => unknown)(...args); + }).toThrow('Initializable: contract not initialized'); + }); + }); + + describe('when initialized correctly', () => { + beforeEach(() => { + token = new FungibleTokenSimulator(NAME, SYMBOL, DECIMALS, INIT); + }); + + describe('totalSupply', () => { + it('returns 0 when there is no supply', () => { + expect(token.totalSupply()).toEqual(0n); + }); + + it('returns the amount of existing tokens when there is a supply', () => { + token._mint(Z_OWNER, AMOUNT); + expect(token.totalSupply()).toEqual(AMOUNT); + }); + }); + + describe('balanceOf', () => { + describe.each(ownerTypes)('when the owner is a %s', (_, owner) => { + it('should return zero when requested account has no balance', () => { + expect(token.balanceOf(owner)).toEqual(0n); + }); + + it('should return balance when requested account has tokens', () => { + token._unsafeMint(owner, AMOUNT); + expect(token.balanceOf(owner)).toEqual(AMOUNT); + }); + }); + }); + + describe('transfer', () => { + beforeEach(() => { + token._mint(Z_OWNER, AMOUNT); + + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); + }); + + afterEach(() => { + expect(token.totalSupply()).toEqual(AMOUNT); + }); + + it('should transfer partial', () => { + const partialAmt = AMOUNT - 1n; + caller = OWNER; + const txSuccess = token.transfer(Z_RECIPIENT, partialAmt, caller); + + expect(txSuccess).toBe(true); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); + }); + + it('should transfer full', () => { + caller = OWNER; + const txSuccess = token.transfer(Z_RECIPIENT, AMOUNT, caller); + + expect(txSuccess).toBe(true); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); + }); + + it('should fail with insufficient balance', () => { + caller = OWNER; + + expect(() => { + token.transfer(Z_RECIPIENT, AMOUNT + 1n, caller); + }).toThrow('FungibleToken: insufficient balance'); + }); + + it('should fail with transfer from zero', () => { + caller = ZERO; + + expect(() => { + token.transfer(Z_RECIPIENT, AMOUNT, caller); + }).toThrow('FungibleToken: invalid sender'); + }); + + it('should fail with transfer to zero', () => { + caller = OWNER; + + expect(() => { + token.transfer(utils.ZERO_KEY, AMOUNT, caller); + }).toThrow('FungibleToken: invalid receiver'); + }); + + it('should allow transfer of 0 tokens', () => { + const txSuccess = token.transfer(Z_RECIPIENT, 0n, caller); + + expect(txSuccess).toBe(true); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); + }); + + it('should handle transfer with empty _balances', () => { + caller = SPENDER; + + expect(() => { + token.transfer(Z_RECIPIENT, 1n, caller); + }).toThrow('FungibleToken: insufficient balance'); + }); + + it('should fail when transferring to a contract', () => { + expect(() => { + token.transfer(Z_OWNER_CONTRACT, AMOUNT); + }).toThrow('FungibleToken: Unsafe Transfer'); + }); + }); + + describe('_unsafeTransfer', () => { + describe.each(recipientTypes)( + 'when the recipient is a %s', + (_, recipient) => { + beforeEach(() => { + token._mint(Z_OWNER, AMOUNT); + + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + expect(token.balanceOf(recipient)).toEqual(0n); + }); + + afterEach(() => { + expect(token.totalSupply()).toEqual(AMOUNT); + }); + + it('should transfer partial', () => { + const partialAmt = AMOUNT - 1n; + caller = OWNER; + const txSuccess = token._unsafeTransfer( + recipient, + partialAmt, + caller, + ); + + expect(txSuccess).toBe(true); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(recipient)).toEqual(partialAmt); + }); + + it('should transfer full', () => { + caller = OWNER; + const txSuccess = token._unsafeTransfer(recipient, AMOUNT, caller); + + expect(txSuccess).toBe(true); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(recipient)).toEqual(AMOUNT); + }); + + it('should fail with insufficient balance', () => { + caller = OWNER; + + expect(() => { + token._unsafeTransfer(recipient, AMOUNT + 1n, caller); + }).toThrow('FungibleToken: insufficient balance'); + }); + + it('should fail with transfer from zero', () => { + caller = ZERO; + + expect(() => { + token._unsafeTransfer(recipient, AMOUNT, caller); + }).toThrow('FungibleToken: invalid sender'); + }); + + it('should allow transfer of 0 tokens', () => { + caller = OWNER; + const txSuccess = token._unsafeTransfer(recipient, 0n, caller); + + expect(txSuccess).toBe(true); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + expect(token.balanceOf(recipient)).toEqual(0n); + }); + + it('should handle transfer with empty _balances', () => { + caller = SPENDER; + + expect(() => { + token._unsafeTransfer(recipient, 1n, caller); + }).toThrow('FungibleToken: insufficient balance'); + }); + }, + ); + + it('should fail with transfer to zero (pk)', () => { + caller = OWNER; + + expect(() => { + token._unsafeTransfer(utils.ZERO_KEY, AMOUNT, caller); + }).toThrow('FungibleToken: invalid receiver'); + }); + + it('should fail with transfer to zero (contract)', () => { + caller = OWNER; + + expect(() => { + token._unsafeTransfer(utils.ZERO_ADDRESS, AMOUNT, caller); + }).toThrow('FungibleToken: invalid receiver'); + }); + }); + + describe('approve', () => { + beforeEach(() => { + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + + it('should approve and update allowance', () => { + caller = OWNER; + + token.approve(Z_SPENDER, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); + }); + + it('should approve and update allowance for multiple spenders', () => { + caller = OWNER; + + token.approve(Z_SPENDER, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); + + token.approve(Z_OTHER, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_OTHER)).toEqual(AMOUNT); + + expect(token.allowance(Z_OWNER, Z_RECIPIENT)).toEqual(0n); + }); + + it('should fail when approve from zero', () => { + caller = ZERO; + + expect(() => { + token.approve(Z_SPENDER, AMOUNT, caller); + }).toThrow('FungibleToken: invalid owner'); + }); + + it('should fail when approve to zero', () => { + caller = OWNER; + + expect(() => { + token.approve(utils.ZERO_KEY, AMOUNT, caller); + }).toThrow('FungibleToken: invalid spender'); + }); + + it('should transfer exact allowance and fail subsequent transfer', () => { + token._mint(Z_OWNER, AMOUNT); + caller = OWNER; + token.approve(Z_SPENDER, AMOUNT, caller); + + caller = SPENDER; + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, 1n, caller); + }).toThrow('FungibleToken: insufficient allowance'); + }); + + it('should allow approve of 0 tokens', () => { + caller = OWNER; + token.approve(Z_SPENDER, 0n, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + + it('should handle allowance with empty _allowances', () => { + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + }); + + describe('transferFrom', () => { + beforeEach(() => { + caller = OWNER; + + token.approve(Z_SPENDER, AMOUNT, caller); + token._mint(Z_OWNER, AMOUNT); + }); + + afterEach(() => { + expect(token.totalSupply()).toEqual(AMOUNT); + }); + + it('should transferFrom spender (partial)', () => { + caller = SPENDER; + const partialAmt = AMOUNT - 1n; + + const txSuccess = token.transferFrom( + Z_OWNER, + Z_RECIPIENT, + partialAmt, + caller, + ); + expect(txSuccess).toBe(true); + + // Check balances + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); + // Check leftover allowance + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(1n); + }); + + it('should transferFrom spender (full)', () => { + caller = SPENDER; + + const txSuccess = token.transferFrom( + Z_OWNER, + Z_RECIPIENT, + AMOUNT, + caller, + ); + expect(txSuccess).toBe(true); + + // Check balances + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); + // Check no allowance + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + + it('should transferFrom and not consume infinite allowance', () => { + caller = OWNER; + token.approve(Z_SPENDER, MAX_UINT128, caller); + + caller = SPENDER; + const txSuccess = token.transferFrom( + Z_OWNER, + Z_RECIPIENT, + AMOUNT, + caller, + ); + expect(txSuccess).toBe(true); + + // Check balances + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); + // Check infinite allowance + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(MAX_UINT128); + }); + + it('should fail when transfer amount exceeds allowance', () => { + caller = SPENDER; + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n); + }).toThrow('FungibleToken: insufficient allowance'); + }); + + it('should fail when transfer amount exceeds balance', () => { + caller = OWNER; + // Increase allowance > balance + token.approve(Z_SPENDER, AMOUNT + 1n, caller); + + caller = SPENDER; + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n, caller); + }).toThrow('FungibleToken: insufficient balance'); + }); + + it('should fail when spender does not have allowance', () => { + caller = UNAUTHORIZED; + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + }).toThrow('FungibleToken: insufficient allowance'); + }); + + it('should fail to transferFrom zero address', () => { + caller = ZERO; + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + }).toThrow('FungibleToken: insufficient allowance'); + }); + + it('should fail to transferFrom to the zero address', () => { + caller = SPENDER; + + expect(() => { + token.transferFrom(Z_OWNER, utils.ZERO_KEY, AMOUNT, caller); + }).toThrow('FungibleToken: invalid receiver'); + }); + + it('should fail when transferring to a contract', () => { + expect(() => { + token.transferFrom(Z_OWNER, Z_OWNER_CONTRACT, AMOUNT, caller); + }).toThrow('FungibleToken: Unsafe Transfer'); + }); + }); + + describe('_unsafeTransferFrom', () => { + beforeEach(() => { + caller = OWNER; + + token.approve(Z_SPENDER, AMOUNT, caller); + token._mint(Z_OWNER, AMOUNT); + }); + + afterEach(() => { + expect(token.totalSupply()).toEqual(AMOUNT); + }); + + describe.each(recipientTypes)( + 'when the recipient is a %s', + (_, recipient) => { + it('should transferFrom spender (partial)', () => { + caller = SPENDER; + const partialAmt = AMOUNT - 1n; + + const txSuccess = token._unsafeTransferFrom( + Z_OWNER, + recipient, + partialAmt, + caller, + ); + expect(txSuccess).toBe(true); + + // Check balances + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(recipient)).toEqual(partialAmt); + // Check leftover allowance + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(1n); + }); + + it('should transferFrom spender (full)', () => { + caller = SPENDER; + + const txSuccess = token._unsafeTransferFrom( + Z_OWNER, + recipient, + AMOUNT, + caller, + ); + expect(txSuccess).toBe(true); + + // Check balances + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(recipient)).toEqual(AMOUNT); + // Check no allowance + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + + it('should transferFrom and not consume infinite allowance', () => { + caller = OWNER; + token.approve(Z_SPENDER, MAX_UINT128, caller); + + caller = SPENDER; + const txSuccess = token._unsafeTransferFrom( + Z_OWNER, + recipient, + AMOUNT, + caller, + ); + expect(txSuccess).toBe(true); + + // Check balances + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(recipient)).toEqual(AMOUNT); + // Check infinite allowance + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(MAX_UINT128); + }); + + it('should fail when transfer amount exceeds allowance', () => { + caller = SPENDER; + + expect(() => { + token._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT + 1n); + }).toThrow('FungibleToken: insufficient allowance'); + }); + + it('should fail when transfer amount exceeds balance', () => { + caller = OWNER; + // Increase allowance > balance + token.approve(Z_SPENDER, AMOUNT + 1n, caller); + + caller = SPENDER; + expect(() => { + token._unsafeTransferFrom( + Z_OWNER, + recipient, + AMOUNT + 1n, + caller, + ); + }).toThrow('FungibleToken: insufficient balance'); + }); + + it('should fail when spender does not have allowance', () => { + caller = UNAUTHORIZED; + + expect(() => { + token._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT, caller); + }).toThrow('FungibleToken: insufficient allowance'); + }); + + it('should fail to transfer from the zero address', () => { + caller = ZERO; + + expect(() => { + token._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT, caller); + }).toThrow('FungibleToken: insufficient allowance'); + }); + }, + ); + + it('should fail to transfer to the zero address (pk)', () => { + caller = SPENDER; + + expect(() => { + token._unsafeTransferFrom(Z_OWNER, utils.ZERO_KEY, AMOUNT, caller); + }).toThrow('FungibleToken: invalid receiver'); + }); + + it('should fail to transfer to the zero address (contract)', () => { + caller = SPENDER; + + expect(() => { + token._unsafeTransferFrom( + Z_OWNER, + utils.ZERO_ADDRESS, + AMOUNT, + caller, + ); + }).toThrow('FungibleToken: invalid receiver'); + }); + }); + + describe('_transfer', () => { + beforeEach(() => { + token._mint(Z_OWNER, AMOUNT); + }); + + afterEach(() => { + expect(token.totalSupply()).toEqual(AMOUNT); + }); + + it('should update balances (partial)', () => { + const partialAmt = AMOUNT - 1n; + token._transfer(Z_OWNER, Z_RECIPIENT, partialAmt); + + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); + }); + + it('should fail when transferring to a contract', () => { + expect(() => { + token._transfer(Z_OWNER, Z_OWNER_CONTRACT, AMOUNT); + }).toThrow('FungibleToken: Unsafe Transfer'); + }); + }); + + describe('_unsafeUncheckedTransfer', () => { + beforeEach(() => { + token._mint(Z_OWNER, AMOUNT); + }); + + afterEach(() => { + expect(token.totalSupply()).toEqual(AMOUNT); + }); + + describe.each(recipientTypes)( + 'when the recipient is a %s', + (_, recipient) => { + it('should update balances (partial)', () => { + const partialAmt = AMOUNT - 1n; + token._unsafeUncheckedTransfer(Z_OWNER, recipient, partialAmt); + + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(recipient)).toEqual(partialAmt); + }); + + it('should update balances (full)', () => { + token._unsafeUncheckedTransfer(Z_OWNER, recipient, AMOUNT); + + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(recipient)).toEqual(AMOUNT); + }); + + it('should fail when transfer amount exceeds balance', () => { + expect(() => { + token._unsafeUncheckedTransfer(Z_OWNER, recipient, AMOUNT + 1n); + }).toThrow('FungibleToken: insufficient balance'); + }); + + it('should fail when transfer from zero', () => { + expect(() => { + token._unsafeUncheckedTransfer( + utils.ZERO_ADDRESS, + recipient, + AMOUNT, + ); + }).toThrow('FungibleToken: invalid sender'); + }); + }, + ); + + it('should fail when transfer to zero (pk)', () => { + expect(() => { + token._unsafeUncheckedTransfer(Z_OWNER, utils.ZERO_KEY, AMOUNT); + }).toThrow('FungibleToken: invalid receiver'); + }); + + it('should fail when transfer to zero (contract)', () => { + expect(() => { + token._unsafeUncheckedTransfer(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); + }).toThrow('FungibleToken: invalid receiver'); + }); + }); + + describe('_mint', () => { + it('should mint and update supply', () => { + expect(token.totalSupply()).toEqual(0n); + + token._mint(Z_RECIPIENT, AMOUNT); + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); + }); + + it('should catch mint overflow', () => { + token._mint(Z_RECIPIENT, MAX_UINT128); + + expect(() => { + token._mint(Z_RECIPIENT, 1n); + }).toThrow('FungibleToken: arithmetic overflow'); + }); + + it('should not mint to zero pubkey', () => { + expect(() => { + token._mint(utils.ZERO_KEY, AMOUNT); + }).toThrow('FungibleToken: invalid receiver'); + }); + + it('should not mint to zero contract address', () => { + expect(() => { + token._mint(utils.ZERO_KEY, AMOUNT); + }).toThrow('FungibleToken: invalid receiver'); + }); + + it('should allow mint of 0 tokens', () => { + token._mint(Z_OWNER, 0n); + expect(token.totalSupply()).toEqual(0n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + + it('should fail when minting to a contract', () => { + expect(() => { + token._mint(Z_OWNER_CONTRACT, AMOUNT); + }).toThrow('FungibleToken: Unsafe Transfer'); + }); + }); + + describe('_unsafeMint', () => { + describe.each(recipientTypes)( + 'when the recipient is a %s', + (_, recipient) => { + it('should mint and update supply', () => { + expect(token.totalSupply()).toEqual(0n); + + token._unsafeMint(recipient, AMOUNT); + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(recipient)).toEqual(AMOUNT); + }); + + it('should catch mint overflow', () => { + token._unsafeMint(recipient, MAX_UINT128); + + expect(() => { + token._unsafeMint(recipient, 1n); + }).toThrow('FungibleToken: arithmetic overflow'); + }); + + it('should allow mint of 0 tokens', () => { + token._unsafeMint(recipient, 0n); + expect(token.totalSupply()).toEqual(0n); + expect(token.balanceOf(recipient)).toEqual(0n); + }); + }, + ); + + it('should not mint to zero pubkey', () => { + expect(() => { + token._unsafeMint(utils.ZERO_KEY, AMOUNT); + }).toThrow('FungibleToken: invalid receiver'); + }); + + it('should not mint to zero contract address', () => { + expect(() => { + token._unsafeMint(utils.ZERO_KEY, AMOUNT); + }).toThrow('FungibleToken: invalid receiver'); + }); + }); + + describe('_burn', () => { + beforeEach(() => { + token._mint(Z_OWNER, AMOUNT); + }); + + it('should burn tokens', () => { + token._burn(Z_OWNER, 1n); + + const afterBurn = AMOUNT - 1n; + expect(token.balanceOf(Z_OWNER)).toEqual(afterBurn); + expect(token.totalSupply()).toEqual(afterBurn); + }); + + it('should throw when burning from zero', () => { + expect(() => { + token._burn(utils.ZERO_KEY, AMOUNT); + }).toThrow('FungibleToken: invalid sender'); + }); + + it('should throw when burn amount is greater than balance', () => { + expect(() => { + token._burn(Z_OWNER, AMOUNT + 1n); + }).toThrow('FungibleToken: insufficient balance'); + }); + + it('should allow burn of 0 tokens', () => { + token._burn(Z_OWNER, 0n); + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + }); + }); + + describe('Multiple Operations', () => { + it('should handle mint → transfer → burn sequence', () => { + token._mint(Z_OWNER, AMOUNT); + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + + caller = OWNER; + token.transfer(Z_RECIPIENT, AMOUNT - 1n, caller); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); + + token._burn(Z_OWNER, 1n); + expect(token.totalSupply()).toEqual(AMOUNT - 1n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + }); + }); +}); diff --git a/contracts/fungibleToken/src/test/mocks/MockFungibleToken.compact b/contracts/fungibleToken/src/test/mocks/MockFungibleToken.compact new file mode 100644 index 00000000..ff6d8167 --- /dev/null +++ b/contracts/fungibleToken/src/test/mocks/MockFungibleToken.compact @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.15.0; + +import CompactStandardLibrary; + +import "../../FungibleToken" prefix FungibleToken_; + +export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; + +/** + * @description `init` is a param for testing. + * If `init` is true, initialize the contract with the + * _name`, `_symbol`, and `_decimals`. + * Otherwise, the contract will not initialize and we can test + * the contract when it is not initialized properly. +*/ +constructor( + _name: Opaque<"string">, + _symbol: Opaque<"string">, + _decimals:Uint<8>, + init: Boolean +) { + if (init) { + FungibleToken_initialize(_name, _symbol, _decimals); + } +} + +export circuit name(): Opaque<"string"> { + return FungibleToken_name(); +} + +export circuit symbol(): Opaque<"string"> { + return FungibleToken_symbol(); +} + +export circuit decimals(): Uint<8> { + return FungibleToken_decimals(); +} + +export circuit totalSupply(): Uint<128> { + return FungibleToken_totalSupply(); +} + +export circuit balanceOf(account: Either): Uint<128> { + return FungibleToken_balanceOf(account); +} + +export circuit allowance( + owner: Either, + spender: Either +): Uint<128> { + return FungibleToken_allowance(owner, spender); +} + +export circuit transfer(to: Either, value: Uint<128>): Boolean { + return FungibleToken_transfer(to, value); +} + +export circuit _unsafeTransfer(to: Either, value: Uint<128>): Boolean { + return FungibleToken__unsafeTransfer(to, value); +} + +export circuit transferFrom( + from: Either, + to: Either, + value: Uint<128> +): Boolean { + return FungibleToken_transferFrom(from, to, value); +} + +export circuit _unsafeTransferFrom( + from: Either, + to: Either, + value: Uint<128> +): Boolean { + return FungibleToken__unsafeTransferFrom(from, to, value); +} + +export circuit approve(spender: Either, value: Uint<128>): Boolean { + return FungibleToken_approve(spender, value); +} + +export circuit _approve( + owner: Either, + spender: Either, + value: Uint<128> +): [] { + return FungibleToken__approve(owner, spender, value); +} + +export circuit _transfer( + from: Either, + to: Either, + value: Uint<128> +): [] { + return FungibleToken__transfer(from, to, value); +} + +export circuit _unsafeUncheckedTransfer( + from: Either, + to: Either, + value: Uint<128> +): [] { + return FungibleToken__unsafeUncheckedTransfer(from, to, value); +} + +export circuit _mint( + account: Either, + value: Uint<128> +): [] { + return FungibleToken__mint(account, value); +} + +export circuit _unsafeMint( + account: Either, + value: Uint<128> +): [] { + return FungibleToken__unsafeMint(account, value); +} + +export circuit _burn( + account: Either, + value: Uint<128> +): [] { + return FungibleToken__burn(account, value); +} + +export circuit _spendAllowance( + owner: Either, + spender: Either, + value: Uint<128> +): [] { + return FungibleToken__spendAllowance(owner, spender, value); +} diff --git a/contracts/fungibleToken/src/test/simulators/FungibleTokenSimulator.ts b/contracts/fungibleToken/src/test/simulators/FungibleTokenSimulator.ts new file mode 100644 index 00000000..fc898583 --- /dev/null +++ b/contracts/fungibleToken/src/test/simulators/FungibleTokenSimulator.ts @@ -0,0 +1,434 @@ +import { + type CircuitContext, + type CoinPublicKey, + type ContractState, + QueryContext, + constructorContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import { sampleContractAddress } from '@midnight-ntwrk/zswap'; +import { + type ContractAddress, + type Either, + type Ledger, + Contract as MockFungibleToken, + type ZswapCoinPublicKey, + ledger, +} from '../../artifacts/MockFungibleToken/contract/index.cjs'; // Combined imports +import { + type FungibleTokenPrivateState, + FungibleTokenWitnesses, +} from '../../witnesses/FungibleTokenWitnesses'; +import type { IContractSimulator } from '../types/test'; + +/** + * @description A simulator implementation of a FungibleToken contract for testing purposes. + * @template P - The private state type, fixed to FungibleTokenPrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class FungibleTokenSimulator + implements IContractSimulator +{ + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockFungibleToken; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor(name: string, symbol: string, decimals: bigint, init: boolean) { + this.contract = new MockFungibleToken( + FungibleTokenWitnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)), + name, + symbol, + decimals, + init, + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type FungibleTokenPrivateState. + */ + public getCurrentPrivateState(): FungibleTokenPrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + + /** + * @description Returns the token name. + * @returns The token name. + */ + public name(): string { + return this.contract.impureCircuits.name(this.circuitContext).result; + } + + /** + * @description Returns the symbol of the token. + * @returns The token name. + */ + public symbol(): string { + return this.contract.impureCircuits.symbol(this.circuitContext).result; + } + + /** + * @description Returns the number of decimals used to get its user representation. + * @returns The account's token balance. + */ + public decimals(): bigint { + return this.contract.impureCircuits.decimals(this.circuitContext).result; + } + + /** + * @description Returns the value of tokens in existence. + * @returns The total supply of tokens. + */ + public totalSupply(): bigint { + return this.contract.impureCircuits.totalSupply(this.circuitContext).result; + } + + /** + * @description Returns the value of tokens owned by `account`. + * @param account The public key or contract address to query. + * @returns The account's token balance. + */ + public balanceOf( + account: Either, + ): bigint { + return this.contract.impureCircuits.balanceOf(this.circuitContext, account) + .result; + } + + /** + * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` + * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. + * @param owner The public key or contract address of approver. + * @param spender The public key or contract address of spender. + * @returns The `spender`'s allowance over `owner`'s tokens. + */ + public allowance( + owner: Either, + spender: Either, + ): bigint { + return this.contract.impureCircuits.allowance( + this.circuitContext, + owner, + spender, + ).result; + } + + /** + * @description Moves a `value` amount of tokens from the caller's account to `to`. + * @param to The recipient of the transfer, either a user or a contract. + * @param value The amount to transfer. + * @param sender The simulated caller. + * @returns As per the IERC20 spec, this MUST return true. + */ + public transfer( + to: Either, + value: bigint, + sender?: CoinPublicKey, + ): boolean { + const res = this.contract.impureCircuits.transfer( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + to, + value, + ); + + this.circuitContext = res.context; + return res.result; + } + + /** + * @description Unsafe variant of `transfer` which allows transfers to contract addresses. + * @param to The recipient of the transfer, either a user or a contract. + * @param value The amount to transfer. + * @param sender The simulated caller. + * @returns As per the IERC20 spec, this MUST return true. + */ + public _unsafeTransfer( + to: Either, + value: bigint, + sender?: CoinPublicKey, + ): boolean { + const res = this.contract.impureCircuits._unsafeTransfer( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + to, + value, + ); + + this.circuitContext = res.context; + return res.result; + } + + /** + * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. + * `value` is the deducted from the caller's allowance. + * @param from The current owner of the tokens for the transfer, either a user or a contract. + * @param to The recipient of the transfer, either a user or a contract. + * @param value The amount to transfer. + * @param sender The simulated caller. + * @returns As per the IERC20 spec, this MUST return true. + */ + public transferFrom( + from: Either, + to: Either, + value: bigint, + sender?: CoinPublicKey, + ): boolean { + const res = this.contract.impureCircuits.transferFrom( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + from, + to, + value, + ); + + this.circuitContext = res.context; + return res.result; + } + + /** + * @description Unsafe variant of `transferFrom` which allows transfers to contract addresses. + * @param from The current owner of the tokens for the transfer, either a user or a contract. + * @param to The recipient of the transfer, either a user or a contract. + * @param value The amount to transfer. + * @param sender The simulated caller. + * @returns As per the IERC20 spec, this MUST return true. + */ + public _unsafeTransferFrom( + from: Either, + to: Either, + value: bigint, + sender?: CoinPublicKey, + ): boolean { + const res = this.contract.impureCircuits._unsafeTransferFrom( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + from, + to, + value, + ); + + this.circuitContext = res.context; + return res.result; + } + + /** + * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. + * @param spender The Zswap key or ContractAddress that may spend on behalf of the caller. + * @param value The amount of tokens the `spender` may spend. + * @param sender The simulated caller. + * @returns Returns a boolean value indicating whether the operation succeeded. + */ + public approve( + spender: Either, + value: bigint, + sender?: CoinPublicKey, + ): boolean { + const res = this.contract.impureCircuits.approve( + { + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + spender, + value, + ); + + this.circuitContext = res.context; + return res.result; + } + + /// + /// Internal + /// + + /** + * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * @param owner The owner of the tokens. + * @param spender The spender of the tokens. + * @param value The amount of tokens `spender` may spend on behalf of `owner`. + * @returns None. + */ + public _approve( + owner: Either, + spender: Either, + value: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._approve( + this.circuitContext, + owner, + spender, + value, + ).context; + } + + /** + * @description Moves a `value` amount of tokens from `from` to `to`. + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * @param from The owner of the tokens to transfer. + * @param to The receipient of the transferred tokens. + * @param value The amount of tokens to transfer. + */ + public _transfer( + from: Either, + to: Either, + value: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._transfer( + this.circuitContext, + from, + to, + value, + ).context; + } + + /** + * @description Unsafe variant of `_transfer` which allows transfers to contract addresses. + * @param from The owner of the tokens to transfer. + * @param to The receipient of the transferred tokens. + * @param value The amount of tokens to transfer. + */ + public _unsafeUncheckedTransfer( + from: Either, + to: Either, + value: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._unsafeUncheckedTransfer( + this.circuitContext, + from, + to, + value, + ).context; + } + + /** + * @description Creates a `value` amount of tokens and assigns them to `account`, + * by transferring it from the zero address. Relies on the `update` mechanism. + * @param account The recipient of tokens minted. + * @param value The amount of tokens minted. + */ + public _mint( + account: Either, + value: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._mint( + this.circuitContext, + account, + value, + ).context; + } + + /** + * @description Unsafe variant of `_mint` which allows transfers to contract addresses. + * @param account The recipient of tokens minted. + * @param value The amount of tokens minted. + */ + public _unsafeMint( + account: Either, + value: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._unsafeMint( + this.circuitContext, + account, + value, + ).context; + } + + /** + * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. + * Relies on the `_update` mechanism. + * @param account The target owner of tokens to burn. + * @param value The amount of tokens to burn. + */ + public _burn( + account: Either, + value: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._burn( + this.circuitContext, + account, + value, + ).context; + } + + /** + * @description Updates `owner`'s allowance for `spender` based on spent `value`. + * Does not update the allowance value in case of infinite allowance. + * @param owner The owner of the tokens. + * @param spender The spender of the tokens. + * @param value The amount of token allowance to spend. + */ + public _spendAllowance( + owner: Either, + spender: Either, + value: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._spendAllowance( + this.circuitContext, + owner, + spender, + value, + ).context; + } +} diff --git a/contracts/fungibleToken/src/test/types/string.ts b/contracts/fungibleToken/src/test/types/string.ts new file mode 100644 index 00000000..430a139e --- /dev/null +++ b/contracts/fungibleToken/src/test/types/string.ts @@ -0,0 +1,4 @@ +export type MaybeString = { + is_some: boolean; + value: string; +}; diff --git a/contracts/fungibleToken/src/test/types/test.ts b/contracts/fungibleToken/src/test/types/test.ts new file mode 100644 index 00000000..7a909543 --- /dev/null +++ b/contracts/fungibleToken/src/test/types/test.ts @@ -0,0 +1,26 @@ +import type { + CircuitContext, + ContractState, +} from '@midnight-ntwrk/compact-runtime'; + +/** + * Generic interface for mock contract implementations. + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + */ +export interface IContractSimulator { + /** The contract's deployed address. */ + readonly contractAddress: string; + + /** The current circuit context. */ + circuitContext: CircuitContext

; + + /** Retrieves the current ledger state. */ + getCurrentPublicState(): L; + + /** Retrieves the current private state. */ + getCurrentPrivateState(): P; + + /** Retrieves the current contract state. */ + getCurrentContractState(): ContractState; +} diff --git a/contracts/fungibleToken/src/test/utils/address.ts b/contracts/fungibleToken/src/test/utils/address.ts new file mode 100644 index 00000000..8c13f417 --- /dev/null +++ b/contracts/fungibleToken/src/test/utils/address.ts @@ -0,0 +1,77 @@ +import { + convert_bigint_to_Uint8Array, + encodeCoinPublicKey, +} from '@midnight-ntwrk/compact-runtime'; +import { encodeContractAddress } from '@midnight-ntwrk/ledger'; +import type * as Compact from '../../artifacts/MockFungibleToken/contract/index.cjs'; + +const PREFIX_ADDRESS = '0200'; + +/** + * @description Converts an ASCII string to its hexadecimal representation, + * left-padded with zeros to a specified length. Useful for generating + * fixed-size hex strings for encoding. + * @param str ASCII string to convert. + * @param len Total desired length of the resulting hex string. Defaults to 64. + * @returns Hexadecimal string representation of `str`, padded to `length` characters. + */ +export const toHexPadded = (str: string, len = 64) => + Buffer.from(str, 'ascii').toString('hex').padStart(len, '0'); + +/** + * @description Generates ZswapCoinPublicKey from `str` for testing purposes. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => ({ + bytes: encodeCoinPublicKey(toHexPadded(str)), +}); + +/** + * @description Generates ContractAddress from `str` for testing purposes. + * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToAddress = (str: string): Compact.ContractAddress => ({ + bytes: encodeContractAddress(PREFIX_ADDRESS + toHexPadded(str)), +}); + +/** + * @description Generates an Either object for ZswapCoinPublicKey for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ZswapCoinPublicKey. + */ +export const createEitherTestUser = (str: string) => ({ + is_left: true, + left: encodeToPK(str), + right: encodeToAddress(''), +}); + +/** + * @description Generates an Either object for ContractAddress for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ContractAddress. + */ +export const createEitherTestContractAddress = (str: string) => ({ + is_left: false, + left: encodeToPK(''), + right: encodeToAddress(str), +}); + +export const zeroUint8Array = (length = 32) => + convert_bigint_to_Uint8Array(length, 0n); + +export const ZERO_KEY = { + is_left: true, + left: { bytes: zeroUint8Array() }, + right: encodeToAddress(''), +}; + +export const ZERO_ADDRESS = { + is_left: false, + left: encodeToPK(''), + right: { bytes: zeroUint8Array() }, +}; diff --git a/contracts/fungibleToken/src/test/utils/test.ts b/contracts/fungibleToken/src/test/utils/test.ts new file mode 100644 index 00000000..d467e572 --- /dev/null +++ b/contracts/fungibleToken/src/test/utils/test.ts @@ -0,0 +1,68 @@ +import { + type CircuitContext, + type CoinPublicKey, + type ContractAddress, + type ContractState, + QueryContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import type { IContractSimulator } from '../types/test'; + +/** + * Constructs a `CircuitContext` from the given state and sender information. + * + * This is typically used at runtime to provide the necessary context + * for executing circuits, including contract state, private state, + * sender identity, and transaction data. + * + * @template P - The type of the contract's private state. + * @param privateState - The current private state of the contract. + * @param contractState - The full contract state, including public and private data. + * @param sender - The public key of the sender (used in the circuit). + * @param contractAddress - The address of the deployed contract. + * @returns A fully populated `CircuitContext` for circuit execution. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContext

( + privateState: P, + contractState: ContractState, + sender: CoinPublicKey, + contractAddress: ContractAddress, +): CircuitContext

{ + return { + originalState: contractState, + currentPrivateState: privateState, + transactionContext: new QueryContext(contractState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} + +/** + * Prepares a new `CircuitContext` using the given sender and contract. + * + * Useful for mocking or updating the circuit context with a custom sender. + * + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + * @template C - The specific type of the contract implementing `MockContract`. + * @param contract - The contract instance implementing `MockContract`. + * @param sender - The public key to set as the sender in the new circuit context. + * @returns A new `CircuitContext` with the sender and updated context values. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContextSender< + P, + L, + C extends IContractSimulator, +>(contract: C, sender: CoinPublicKey): CircuitContext

{ + const currentPrivateState = contract.getCurrentPrivateState(); + const originalState = contract.getCurrentContractState(); + const contractAddress = contract.contractAddress; + + return { + originalState, + currentPrivateState, + transactionContext: new QueryContext(originalState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} diff --git a/contracts/fungibleToken/src/witnesses/FungibleTokenWitnesses.ts b/contracts/fungibleToken/src/witnesses/FungibleTokenWitnesses.ts new file mode 100644 index 00000000..2d9d8030 --- /dev/null +++ b/contracts/fungibleToken/src/witnesses/FungibleTokenWitnesses.ts @@ -0,0 +1,3 @@ +// This is how we type an empty object. +export type FungibleTokenPrivateState = Record; +export const FungibleTokenWitnesses = {}; diff --git a/contracts/fungibleToken/tsconfig.build.json b/contracts/fungibleToken/tsconfig.build.json new file mode 100644 index 00000000..f1132509 --- /dev/null +++ b/contracts/fungibleToken/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["src/test/**/*.ts"], + "compilerOptions": {} +} diff --git a/contracts/fungibleToken/tsconfig.json b/contracts/fungibleToken/tsconfig.json new file mode 100644 index 00000000..3e90b0a9 --- /dev/null +++ b/contracts/fungibleToken/tsconfig.json @@ -0,0 +1,21 @@ +{ + "include": ["src/**/*.ts"], + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "lib": ["ESNext"], + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "node", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": true, + "strict": true, + "isolatedModules": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true + } +} diff --git a/contracts/erc20/turbo.json b/contracts/fungibleToken/turbo.json similarity index 100% rename from contracts/erc20/turbo.json rename to contracts/fungibleToken/turbo.json diff --git a/contracts/fungibleToken/vitest.config.ts b/contracts/fungibleToken/vitest.config.ts new file mode 100644 index 00000000..785b792e --- /dev/null +++ b/contracts/fungibleToken/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['src/test/**/*.test.ts'], + reporters: 'verbose', + }, +}); diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index 9995020c..415b5b4f 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -15,7 +15,7 @@ module Utils { * @notice Midnight's burn address is represented as left(default) * in Compact, so we've chosen to represent the zero address as this structure as well. * - * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @param {Either} keyOrAddress - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @return {Boolean} - Returns true if `keyOrAddress` is zero. */ export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { @@ -38,7 +38,11 @@ module Utils { } /** +<<<<<<< HEAD * @description Returns whether `keyOrAddress` is equal to `other`. Assumes that a ZswapCoinPublicKey +======= + * @description Returns whether `keyOrAddress` is equal to `other`. Assumes that a ZswapCoinPublicKey +>>>>>>> 4f20422 (Update fungible token (#125)) * and a ContractAddress can never be equal * * @param {Either} keyOrAddress - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. @@ -67,6 +71,7 @@ module Utils { export pure circuit isContractAddress(keyOrAddress: Either): Boolean { return !keyOrAddress.is_left; } +<<<<<<< HEAD /** * @description A helper function that returns the empty string: "" @@ -76,4 +81,6 @@ module Utils { export pure circuit emptyString(): Opaque<"string"> { return default>; } +======= +>>>>>>> 4f20422 (Update fungible token (#125)) } diff --git a/contracts/utils/src/test/mocks/MockUtils.compact b/contracts/utils/src/test/mocks/MockUtils.compact index eaeb3d18..2f481ddc 100644 --- a/contracts/utils/src/test/mocks/MockUtils.compact +++ b/contracts/utils/src/test/mocks/MockUtils.compact @@ -28,3 +28,18 @@ export pure circuit isContractAddress(keyOrAddress: Either { return Utils_emptyString(); } + +export pure circuit isKeyOrAddressEqual( + keyOrAddress: Either, + other: Either +): Boolean { + return Utils_isKeyOrAddressEqual(keyOrAddress, other); +} + +export pure circuit isKeyZero(key: ZswapCoinPublicKey): Boolean { + return Utils_isKeyZero(key); +} + +export pure circuit isContractAddress(keyOrAddress: Either): Boolean { + return Utils_isContractAddress(keyOrAddress); +} diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index faca5b73..39bf24b1 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -8,8 +8,11 @@ const SOME_CONTRACT = contractUtils.createEitherTestContractAddress('SOME_CONTRACT'); const OTHER_CONTRACT = contractUtils.createEitherTestContractAddress('OTHER_CONTRACT'); +<<<<<<< HEAD const EMPTY_STRING = ''; +======= +>>>>>>> 4f20422 (Update fungible token (#125)) let contract: UtilsSimulator; @@ -98,4 +101,52 @@ describe('Utils', () => { expect(contract.emptyString()).toBe(EMPTY_STRING); }); }); + + describe('isKeyOrAddressEqual', () => { + it('should return true for two matching pubkeys', () => { + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_SOME_KEY)).toBe(true); + }); + + it('should return true for two matching contract addresses', () => { + expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, SOME_CONTRACT)).toBe( + true, + ); + }); + + it('should return false for two different pubkeys', () => { + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_OTHER_KEY)).toBe(false); + }); + + it('should return false for two different contract addresses', () => { + expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, OTHER_CONTRACT)).toBe( + false, + ); + }); + + it('should return false for two different address types', () => { + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, SOME_CONTRACT)).toBe( + false, + ); + }); + }); + + describe('isKeyZero', () => { + it('should return zero for the zero address', () => { + expect(contract.isKeyZero(contractUtils.ZERO_KEY.left)).toBe(true); + }); + + it('should not return zero for nonzero addresses', () => { + expect(contract.isKeyZero(Z_SOME_KEY.left)).toBe(false); + }); + }); + + describe('isContractAddress', () => { + it('should return true if ContractAddress', () => { + expect(contract.isContractAddress(SOME_CONTRACT)).toBe(true); + }); + + it('should return false ZswapCoinPublicKey', () => { + expect(contract.isContractAddress(Z_SOME_KEY)).toBe(false); + }); + }); }); diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 5371e49a..d110117f 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -48,9 +48,9 @@ Compile the contracts: $ npx turbo compact (...) -✔ [COMPILE] [1/2] Compiled ERC20.compact -@openzeppelin-midnight/erc20:compact: Compactc version: 0.23.0 -@openzeppelin-midnight/erc20:compact: +✔ [COMPILE] [1/2] Compiled FungibleToken.compact +@openzeppelin-midnight/fungible-token:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/fungible-token:compact: ✔ [COMPILE] [1/6] Compiled Initializable.compact @openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 @openzeppelin-midnight/utils:compact: @@ -70,9 +70,9 @@ $ npx turbo compact @openzeppelin-midnight/utils:compact: Compactc version: 0.23.0 @openzeppelin-midnight/utils:compact: -✔ [COMPILE] [2/2] Compiled test/mocks/MockERC20.compact -@openzeppelin-midnight/erc20:compact: Compactc version: 0.23.0 -@openzeppelin-midnight/erc20:compact: Compiling 15 circuits: +✔ [COMPILE] [2/2] Compiled test/mocks/MockFungibleToken.compact +@openzeppelin-midnight/fungible-token:compact: Compactc version: 0.23.0 +@openzeppelin-midnight/fungible-token:compact: Compiling 15 circuits: Tasks: 2 successful, 2 total diff --git a/yarn.lock b/yarn.lock index b6a8ade5..621e3b2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -392,7 +392,6 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/compact@workspace:compact" dependencies: - "@types/node": "npm:22.14.0" "@types/node": "npm:22.14.0" chalk: "npm:^5.4.1" fast-check: "npm:^3.15.0" @@ -405,9 +404,9 @@ __metadata: languageName: unknown linkType: soft -"@openzeppelin-midnight/erc20@workspace:contracts/erc20": +"@openzeppelin-midnight/fungible-token@workspace:contracts/fungibleToken": version: 0.0.0-use.local - resolution: "@openzeppelin-midnight/erc20@workspace:contracts/erc20" + resolution: "@openzeppelin-midnight/fungible-token@workspace:contracts/fungibleToken" dependencies: "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:22.14.0" @@ -417,26 +416,12 @@ __metadata: languageName: unknown linkType: soft -"@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken": - version: 0.0.0-use.local - resolution: "@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken" - dependencies: - "@biomejs/biome": "npm:1.9.4" - "@openzeppelin-midnight/compact": "workspace:^" - "@types/node": "npm:^22.14.0" - ts-node: "npm:^10.9.2" - typescript: "npm:^5.2.2" - vitest: "npm:^3.1.3" - languageName: unknown - linkType: soft - "@openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" dependencies: "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:22.14.0" - "@types/node": "npm:22.14.0" ts-node: "npm:^10.9.2" typescript: "npm:^5.2.2" vitest: "npm:^3.1.3" @@ -676,7 +661,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^22, @types/node@npm:^22.14.0": +"@types/node@npm:^22": version: 22.15.32 resolution: "@types/node@npm:22.15.32" dependencies: From 314d2e9d2333fe24afc2d0182252bb1cf31ebea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:38:17 -0400 Subject: [PATCH 243/282] Update yarn.lock --- yarn.lock | 197 +++++++++++++++++++++++++++--------------------------- 1 file changed, 98 insertions(+), 99 deletions(-) diff --git a/yarn.lock b/yarn.lock index 621e3b2c..5c3e90e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -454,142 +454,142 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.43.0" +"@rollup/rollup-android-arm-eabi@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.44.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-android-arm64@npm:4.43.0" +"@rollup/rollup-android-arm64@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-android-arm64@npm:4.44.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-darwin-arm64@npm:4.43.0" +"@rollup/rollup-darwin-arm64@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.44.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-darwin-x64@npm:4.43.0" +"@rollup/rollup-darwin-x64@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.44.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.43.0" +"@rollup/rollup-freebsd-arm64@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.44.0" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-freebsd-x64@npm:4.43.0" +"@rollup/rollup-freebsd-x64@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.44.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.43.0" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.44.0" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.43.0" +"@rollup/rollup-linux-arm-musleabihf@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.44.0" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.43.0" +"@rollup/rollup-linux-arm64-gnu@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.44.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.43.0" +"@rollup/rollup-linux-arm64-musl@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.44.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-loongarch64-gnu@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.43.0" +"@rollup/rollup-linux-loongarch64-gnu@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.44.0" conditions: os=linux & cpu=loong64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-powerpc64le-gnu@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.43.0" +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.44.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.43.0" +"@rollup/rollup-linux-riscv64-gnu@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.44.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-musl@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.43.0" +"@rollup/rollup-linux-riscv64-musl@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.44.0" conditions: os=linux & cpu=riscv64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.43.0" +"@rollup/rollup-linux-s390x-gnu@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.44.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.43.0" +"@rollup/rollup-linux-x64-gnu@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.44.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.43.0" +"@rollup/rollup-linux-x64-musl@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.44.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.43.0" +"@rollup/rollup-win32-arm64-msvc@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.44.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.43.0" +"@rollup/rollup-win32-ia32-msvc@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.44.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.43.0": - version: 4.43.0 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.43.0" +"@rollup/rollup-win32-x64-msvc@npm:4.44.0": + version: 4.44.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.44.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -638,14 +638,7 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:1.0.7": - version: 1.0.7 - resolution: "@types/estree@npm:1.0.7" - checksum: 10/419c845ece767ad4b21171e6e5b63dabb2eb46b9c0d97361edcd9cabbf6a95fcadb91d89b5fa098d1336fa0b8fceaea82fca97a2ef3971f5c86e53031e157b21 - languageName: node - linkType: hard - -"@types/estree@npm:^1.0.0": +"@types/estree@npm:1.0.8, @types/estree@npm:^1.0.0": version: 1.0.8 resolution: "@types/estree@npm:1.0.8" checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099 @@ -661,12 +654,18 @@ __metadata: languageName: node linkType: hard +<<<<<<< HEAD "@types/node@npm:^22": version: 22.15.32 resolution: "@types/node@npm:22.15.32" +======= +"@types/node@npm:^22.14.0": + version: 22.15.33 + resolution: "@types/node@npm:22.15.33" +>>>>>>> 29d6e3f (Update yarn.lock) dependencies: undici-types: "npm:~6.21.0" - checksum: 10/10b4c106d0c512a1d35ec08142bd7fb5cf2e1df93fc5627b3c69dd843dec4be07a47f1fa7ede232ad84762d75a372ea35028b79ee1e753b6f2adecd0b2cb2f71 + checksum: 10/5734cbca7fc363f3d6ad191e1be645cc9885d642e9f90688892459f10629cf663d2206e7ed7b255dd476baaa86fb011aa09647e77520958b5993b391f793856f languageName: node linkType: hard @@ -1937,7 +1936,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.5.5": +"postcss@npm:^8.5.6": version: 8.5.6 resolution: "postcss@npm:8.5.6" dependencies: @@ -1999,30 +1998,30 @@ __metadata: linkType: hard "rollup@npm:^4.40.0": - version: 4.43.0 - resolution: "rollup@npm:4.43.0" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.43.0" - "@rollup/rollup-android-arm64": "npm:4.43.0" - "@rollup/rollup-darwin-arm64": "npm:4.43.0" - "@rollup/rollup-darwin-x64": "npm:4.43.0" - "@rollup/rollup-freebsd-arm64": "npm:4.43.0" - "@rollup/rollup-freebsd-x64": "npm:4.43.0" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.43.0" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.43.0" - "@rollup/rollup-linux-arm64-gnu": "npm:4.43.0" - "@rollup/rollup-linux-arm64-musl": "npm:4.43.0" - "@rollup/rollup-linux-loongarch64-gnu": "npm:4.43.0" - "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.43.0" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.43.0" - "@rollup/rollup-linux-riscv64-musl": "npm:4.43.0" - "@rollup/rollup-linux-s390x-gnu": "npm:4.43.0" - "@rollup/rollup-linux-x64-gnu": "npm:4.43.0" - "@rollup/rollup-linux-x64-musl": "npm:4.43.0" - "@rollup/rollup-win32-arm64-msvc": "npm:4.43.0" - "@rollup/rollup-win32-ia32-msvc": "npm:4.43.0" - "@rollup/rollup-win32-x64-msvc": "npm:4.43.0" - "@types/estree": "npm:1.0.7" + version: 4.44.0 + resolution: "rollup@npm:4.44.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.44.0" + "@rollup/rollup-android-arm64": "npm:4.44.0" + "@rollup/rollup-darwin-arm64": "npm:4.44.0" + "@rollup/rollup-darwin-x64": "npm:4.44.0" + "@rollup/rollup-freebsd-arm64": "npm:4.44.0" + "@rollup/rollup-freebsd-x64": "npm:4.44.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.44.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.44.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.44.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.44.0" + "@rollup/rollup-linux-loongarch64-gnu": "npm:4.44.0" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.44.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.44.0" + "@rollup/rollup-linux-riscv64-musl": "npm:4.44.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.44.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.44.0" + "@rollup/rollup-linux-x64-musl": "npm:4.44.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.44.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.44.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.44.0" + "@types/estree": "npm:1.0.8" fsevents: "npm:~2.3.2" dependenciesMeta: "@rollup/rollup-android-arm-eabi": @@ -2069,7 +2068,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10/c7f436880dfd5bd54e9ac579625b5355be58b5437ebb386eb88d709d6bed733a4411673cc80fd64dc5514cd71794544bc83775842108c86ed2b51827e11b33b8 + checksum: 10/2182fc751734277972c011bf62a07cd01de44aaa408f29d3be51b6c7373aa179c9e20d5b9b9fa46268c7d65fc8edb033243f501495465b13dd05d1f99635a7fa languageName: node linkType: hard @@ -2512,14 +2511,14 @@ __metadata: linkType: hard "vite@npm:^5.0.0 || ^6.0.0 || ^7.0.0-0": - version: 7.0.0-beta.2 - resolution: "vite@npm:7.0.0-beta.2" + version: 7.0.0 + resolution: "vite@npm:7.0.0" dependencies: esbuild: "npm:^0.25.0" fdir: "npm:^6.4.6" fsevents: "npm:~2.3.3" picomatch: "npm:^4.0.2" - postcss: "npm:^8.5.5" + postcss: "npm:^8.5.6" rollup: "npm:^4.40.0" tinyglobby: "npm:^0.2.14" peerDependencies: @@ -2562,7 +2561,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10/01245969939849d2a1fbfc6bba95b80079ecaf2a181bf530a35718bc8e093b49f92c0d228e64e7cf8d1976fdf77da5ca4ff0fd8d8e1df6bd81830c51c79e3b98 + checksum: 10/2501b706dc481529efb16c6241794a66d68ea7a074d49f22e45b701769fbeeccc721c58272c9fce743d3b1472a3de497f85ca18cb059b1b8b906b2b295e524dc languageName: node linkType: hard From 41dc60ba5c6465db8982f0b233b97ec8fca9bc1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:38:27 -0400 Subject: [PATCH 244/282] Fmt file --- contracts/fungibleToken/src/FungibleToken.compact | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/fungibleToken/src/FungibleToken.compact b/contracts/fungibleToken/src/FungibleToken.compact index 7c53ad02..4d2f01d5 100644 --- a/contracts/fungibleToken/src/FungibleToken.compact +++ b/contracts/fungibleToken/src/FungibleToken.compact @@ -66,7 +66,7 @@ module FungibleToken { export sealed ledger _name: Opaque<"string">; export sealed ledger _symbol: Opaque<"string">; export sealed ledger _decimals: Uint<8>; - + /** * @description Initializes the contract by setting the name, symbol, and decimals. * @dev This MUST be called in the implementing contract's constructor. Failure to do so From e9b38a39c9e3d960063a4364d93c1c34d1242517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:40:07 -0400 Subject: [PATCH 245/282] File extension required with nodenext --- contracts/fungibleToken/src/test/FungibleToken.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/fungibleToken/src/test/FungibleToken.test.ts b/contracts/fungibleToken/src/test/FungibleToken.test.ts index 3939491c..3336bbac 100644 --- a/contracts/fungibleToken/src/test/FungibleToken.test.ts +++ b/contracts/fungibleToken/src/test/FungibleToken.test.ts @@ -1,7 +1,7 @@ import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { FungibleTokenSimulator } from './simulators/FungibleTokenSimulator'; -import * as utils from './utils/address'; +import { FungibleTokenSimulator } from './simulators/FungibleTokenSimulator.js'; +import * as utils from './utils/address.js'; // Metadata const EMPTY_STRING = ''; From f4d38bfc1206fd77c5f064f1b8e954bd7660a28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:41:21 -0400 Subject: [PATCH 246/282] Remove deleted import, reorganize code, improve readability, remove _update tests --- .../src/test/nonFungibleToken.test.ts | 173 ++++-------------- 1 file changed, 31 insertions(+), 142 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts index bd368164..8fc5e6e9 100644 --- a/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts +++ b/contracts/nonFungibleToken/src/test/nonFungibleToken.test.ts @@ -1,36 +1,36 @@ import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; import { beforeEach, describe, expect, it } from 'vitest'; import { NonFungibleTokenSimulator } from './simulators/NonFungibleTokenSimulator.js'; -import { UninitializedNonFungibleTokenSimulator } from './simulators/UninitializedNonFungibleTokenSimulator.js'; import { ZERO_ADDRESS, ZERO_KEY, createEitherTestContractAddress, createEitherTestUser, + toHexPadded, } from './utils/address.js'; -const SOME_STRING = 'https://openzeppelin.example'; +// Contract Metadata const NAME = 'NAME'; const SYMBOL = 'SYMBOL'; const EMPTY_STRING = ''; +const INIT = true; +const BAD_INIT = false; +// Token Metadata const TOKENID_1: bigint = BigInt(1); const TOKENID_2: bigint = BigInt(2); const TOKENID_3: bigint = BigInt(3); const NON_EXISTENT_TOKEN: bigint = BigInt(0xdead); +const SOME_URI = 'https://openzeppelin.example'; +const EMPTY_URI = ''; const AMOUNT: bigint = BigInt(1); -const OWNER = String(Buffer.from('OWNER', 'ascii').toString('hex')).padStart( - 64, - '0', -); -const SPENDER = String( - Buffer.from('SPENDER', 'ascii').toString('hex'), -).padStart(64, '0'); -const UNAUTHORIZED = String( - Buffer.from('UNAUTHORIZED', 'ascii').toString('hex'), -).padStart(64, '0'); +// Callers +const OWNER = toHexPadded('OWNER'); +const SPENDER = toHexPadded('SPENDER'); +const UNAUTHORIZED = toHexPadded('UNAUTHORIZED'); +// Encoded PK/Addresses const Z_OWNER = createEitherTestUser('OWNER'); const Z_SPENDER = createEitherTestUser('SPENDER'); const Z_RECIPIENT = createEitherTestUser('RECIPIENT'); @@ -44,27 +44,27 @@ let _caller: CoinPublicKey; describe('NonFungibleToken', () => { describe('initializer and metadata', () => { it('should initialize metadata', () => { - token = new NonFungibleTokenSimulator(NAME, SYMBOL); + token = new NonFungibleTokenSimulator(NAME, SYMBOL, INIT); expect(token.name()).toEqual(NAME); expect(token.symbol()).toEqual(SYMBOL); }); it('should initialize empty metadata', () => { - token = new NonFungibleTokenSimulator(EMPTY_STRING, EMPTY_STRING); + token = new NonFungibleTokenSimulator(EMPTY_STRING, EMPTY_STRING, INIT); expect(token.name()).toEqual(EMPTY_STRING); expect(token.symbol()).toEqual(EMPTY_STRING); }); it('should initialize metadata with whitespace', () => { - token = new NonFungibleTokenSimulator(' NAME ', ' SYMBOL '); + token = new NonFungibleTokenSimulator(' NAME ', ' SYMBOL ', INIT); expect(token.name()).toEqual(' NAME '); expect(token.symbol()).toEqual(' SYMBOL '); }); it('should initialize metadata with special characters', () => { - token = new NonFungibleTokenSimulator('NAME!@#', 'SYMBOL$%^'); + token = new NonFungibleTokenSimulator('NAME!@#', 'SYMBOL$%^', INIT); expect(token.name()).toEqual('NAME!@#'); expect(token.symbol()).toEqual('SYMBOL$%^'); }); @@ -72,14 +72,14 @@ describe('NonFungibleToken', () => { it('should initialize metadata with very long strings', () => { const longName = 'A'.repeat(1000); const longSymbol = 'B'.repeat(1000); - token = new NonFungibleTokenSimulator(longName, longSymbol); + token = new NonFungibleTokenSimulator(longName, longSymbol, INIT); expect(token.name()).toEqual(longName); expect(token.symbol()).toEqual(longSymbol); }); }); beforeEach(() => { - token = new NonFungibleTokenSimulator(NAME, SYMBOL); + token = new NonFungibleTokenSimulator(NAME, SYMBOL, INIT); }); describe('balanceOf', () => { @@ -177,17 +177,17 @@ describe('NonFungibleToken', () => { }); it('should return the empty string for an unset tokenURI', () => { - expect(token.tokenURI(TOKENID_1)).toEqual(EMPTY_STRING); + expect(token.tokenURI(TOKENID_1)).toEqual(EMPTY_URI); }); it('should return the empty string if tokenURI set as default value', () => { - token._setTokenURI(TOKENID_1, EMPTY_STRING); - expect(token.tokenURI(TOKENID_1)).toEqual(EMPTY_STRING); + token._setTokenURI(TOKENID_1, EMPTY_URI); + expect(token.tokenURI(TOKENID_1)).toEqual(EMPTY_URI); }); it('should return some string if tokenURI is set', () => { - token._setTokenURI(TOKENID_1, SOME_STRING); - expect(token.tokenURI(TOKENID_1)).toEqual(SOME_STRING); + token._setTokenURI(TOKENID_1, SOME_URI); + expect(token.tokenURI(TOKENID_1)).toEqual(SOME_URI); }); it('should return very long tokenURI', () => { @@ -210,9 +210,9 @@ describe('NonFungibleToken', () => { }); it('should maintain tokenURI after token transfer', () => { - token._setTokenURI(TOKENID_1, SOME_STRING); + token._setTokenURI(TOKENID_1, SOME_URI); token._transfer(Z_OWNER, Z_RECIPIENT, TOKENID_1); - expect(token.tokenURI(TOKENID_1)).toEqual(SOME_STRING); + expect(token.tokenURI(TOKENID_1)).toEqual(SOME_URI); }); }); @@ -592,116 +592,6 @@ describe('NonFungibleToken', () => { }); }); - describe('_update', () => { - it('should transfer token and clear approvals', () => { - _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); - token.approve(Z_OTHER, TOKENID_1, _caller); - expect(token.getApproved(TOKENID_1)).toEqual(Z_OTHER); - const prevOwner = token._update(Z_SPENDER, TOKENID_1, ZERO_KEY); - - expect(prevOwner).toEqual(Z_OWNER); - expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token.balanceOf(Z_SPENDER)).toEqual(1n); - expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); - }); - - it('should mint a token', () => { - const prevOwner = token._update(Z_OWNER, TOKENID_1, ZERO_KEY); - expect(prevOwner).toEqual(ZERO_KEY); - expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - }); - - it('should burn a token', () => { - token._mint(Z_OWNER, TOKENID_1); - const prevOwner = token._update(ZERO_KEY, TOKENID_1, Z_OWNER); - expect(prevOwner).toEqual(Z_OWNER); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token._ownerOf(TOKENID_1)).toEqual(ZERO_KEY); - }); - - it('should transfer if auth is authorized', () => { - _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); - token.approve(Z_SPENDER, TOKENID_1, _caller); - const prevOwner = token._update(Z_SPENDER, TOKENID_1, Z_SPENDER); - - expect(prevOwner).toEqual(Z_OWNER); - expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token.balanceOf(Z_SPENDER)).toEqual(1n); - }); - - it('should transfer if auth is authorized for all', () => { - _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); - token.setApprovalForAll(Z_SPENDER, true, _caller); - const prevOwner = token._update(Z_SPENDER, TOKENID_1, Z_SPENDER); - - expect(prevOwner).toEqual(Z_OWNER); - expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token.balanceOf(Z_SPENDER)).toEqual(1n); - }); - - it('should throw if auth is not authorized', () => { - _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); - expect(() => { - token._update(Z_SPENDER, TOKENID_1, Z_SPENDER); - }).toThrow('NonFungibleToken: Insufficient Approval'); - }); - - it('should update multiple tokens in sequence', () => { - _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); - token._mint(Z_OWNER, TOKENID_2); - token._mint(Z_OWNER, TOKENID_3); - token.approve(Z_SPENDER, TOKENID_1, _caller); - token.approve(Z_SPENDER, TOKENID_2, _caller); - token.approve(Z_SPENDER, TOKENID_3, _caller); - - token._update(Z_SPENDER, TOKENID_1, Z_SPENDER); - token._update(Z_SPENDER, TOKENID_2, Z_SPENDER); - token._update(Z_SPENDER, TOKENID_3, Z_SPENDER); - - expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); - expect(token.ownerOf(TOKENID_2)).toEqual(Z_SPENDER); - expect(token.ownerOf(TOKENID_3)).toEqual(Z_SPENDER); - }); - - it('should update with very long token IDs', () => { - _caller = OWNER; - const longTokenId = BigInt('18446744073709551615'); - token._mint(Z_OWNER, longTokenId); - token.approve(Z_SPENDER, longTokenId, _caller); - token._update(Z_SPENDER, longTokenId, Z_SPENDER); - expect(token.ownerOf(longTokenId)).toEqual(Z_SPENDER); - }); - - it('should update after multiple transfers', () => { - _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); - token._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); - _caller = SPENDER; - token.approve(Z_OTHER, TOKENID_1, _caller); - token._update(Z_OTHER, TOKENID_1, Z_OTHER); - expect(token.ownerOf(TOKENID_1)).toEqual(Z_OTHER); - }); - - it('should update after multiple burns', () => { - _caller = OWNER; - token._mint(Z_OWNER, TOKENID_1); - token._burn(TOKENID_1); - token._mint(Z_OWNER, TOKENID_1); - token.approve(Z_SPENDER, TOKENID_1, _caller); - token._update(Z_SPENDER, TOKENID_1, Z_SPENDER); - expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); - }); - }); - describe('_approve', () => { it('should approve if auth is owner', () => { token._mint(Z_OWNER, TOKENID_1); @@ -1004,14 +894,14 @@ describe('NonFungibleToken', () => { describe('_setTokenURI', () => { it('should throw if token does not exist', () => { expect(() => { - token._setTokenURI(NON_EXISTENT_TOKEN, EMPTY_STRING); + token._setTokenURI(NON_EXISTENT_TOKEN, EMPTY_URI); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should set tokenURI', () => { token._mint(Z_OWNER, TOKENID_1); - token._setTokenURI(TOKENID_1, SOME_STRING); - expect(token.tokenURI(TOKENID_1)).toEqual(SOME_STRING); + token._setTokenURI(TOKENID_1, SOME_URI); + expect(token.tokenURI(TOKENID_1)).toEqual(SOME_URI); }); }); @@ -1198,7 +1088,7 @@ describe('NonFungibleToken', () => { }); type FailingCircuits = [ - method: keyof UninitializedNonFungibleTokenSimulator, + method: keyof NonFungibleTokenSimulator, args: unknown[], ]; // Circuit calls should fail before the args are used @@ -1215,7 +1105,6 @@ const circuitsToFail: FailingCircuits[] = [ ['transferFrom', [Z_OWNER, Z_RECIPIENT, TOKENID_1]], ['_requireOwned', [TOKENID_1]], ['_ownerOf', [TOKENID_1]], - ['_update', [Z_SPENDER, TOKENID_1, Z_OWNER]], ['_approve', [Z_OWNER, TOKENID_1, Z_SPENDER]], ['_checkAuthorized', [Z_OWNER, Z_SPENDER, TOKENID_1]], ['_isAuthorized', [Z_OWNER, Z_SPENDER, TOKENID_1]], @@ -1230,11 +1119,11 @@ const circuitsToFail: FailingCircuits[] = [ ['_unsafeMint', [Z_OWNER, TOKENID_1]], ]; -let uninitializedToken: UninitializedNonFungibleTokenSimulator; +let uninitializedToken: NonFungibleTokenSimulator; describe('Uninitialized NonFungibleToken', () => { beforeEach(() => { - uninitializedToken = new UninitializedNonFungibleTokenSimulator(); + uninitializedToken = new NonFungibleTokenSimulator(NAME, SYMBOL, BAD_INIT); }); it.each(circuitsToFail)('%s should fail', (circuitName, args) => { From f43c4f6d282483cdaef9e35efeeccc0af850a68e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:41:36 -0400 Subject: [PATCH 247/282] Delete files --- .../MockUninitializedNonFungibleToken.compact | 158 ---- .../mocks/NonFungibleTokenTesting.compact | 679 ------------------ .../UninitializedNonFungibleTokenSimulator.ts | 635 ---------------- 3 files changed, 1472 deletions(-) delete mode 100644 contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact delete mode 100644 contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact delete mode 100644 contracts/nonFungibleToken/src/test/simulators/UninitializedNonFungibleTokenSimulator.ts diff --git a/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact b/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact deleted file mode 100644 index 1c081109..00000000 --- a/contracts/nonFungibleToken/src/test/mocks/MockUninitializedNonFungibleToken.compact +++ /dev/null @@ -1,158 +0,0 @@ -pragma language_version >= 0.15.0; - -import CompactStandardLibrary; - -import "NonFungibleTokenTesting" prefix NonFungibleToken_; - -export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; - -export circuit name(): Opaque<"string"> { - return NonFungibleToken_name(); -} - -export circuit symbol(): Opaque<"string"> { - return NonFungibleToken_symbol(); -} - -export circuit balanceOf(account: Either): Uint<128> { - return NonFungibleToken_balanceOf(account); -} - -export circuit ownerOf(tokenId: Uint<128>): Either { - return NonFungibleToken_ownerOf(tokenId); -} - -export circuit tokenURI(tokenId: Uint<128>): Opaque<"string"> { - return NonFungibleToken_tokenURI(tokenId); -} - -export circuit approve( - to: Either, - tokenId: Uint<128> -): [] { - return NonFungibleToken_approve(to, tokenId); -} - -export circuit getApproved(tokenId: Uint<128>): Either { - return NonFungibleToken_getApproved(tokenId); -} - -export circuit setApprovalForAll( - operator: Either, - approved: Boolean -): [] { - return NonFungibleToken_setApprovalForAll(operator, approved); -} - -export circuit isApprovedForAll( - owner: Either, - operator: Either -): Boolean { - return NonFungibleToken_isApprovedForAll(owner, operator); -} - -export circuit transferFrom( - from: Either, - to: Either, - tokenId: Uint<128> -): [] { - return NonFungibleToken_transferFrom(from, to, tokenId); -} - -export circuit _requireOwned(tokenId: Uint<128>): Either { - return NonFungibleToken__requireOwned(tokenId); -} - -export circuit _ownerOf(tokenId: Uint<128>): Either { - return NonFungibleToken__ownerOf(tokenId); -} - -export circuit _update( - to: Either, - tokenId: Uint<128>, - auth: Either -): Either { - return NonFungibleToken__update(to, tokenId, auth); -} - -export circuit _approve( - to: Either, - tokenId: Uint<128>, - auth: Either -): [] { - return NonFungibleToken__approve(to, tokenId, auth); -} - -export circuit _checkAuthorized( - owner: Either, - spender: Either, - tokenId: Uint<128> -): [] { - return NonFungibleToken__checkAuthorized(owner, spender, tokenId); -} - -export circuit _isAuthorized( - owner: Either, - spender: Either, - tokenId: Uint<128> -): Boolean { - return NonFungibleToken__isAuthorized(owner, spender, tokenId); -} - -export circuit _getApproved(tokenId: Uint<128>): Either { - return NonFungibleToken__getApproved(tokenId); -} - -export circuit _setApprovalForAll( - owner: Either, - operator: Either, - approved: Boolean -): [] { - return NonFungibleToken__setApprovalForAll(owner, operator, approved); -} - -export circuit _mint( - to: Either, - tokenId: Uint<128> -): [] { - return NonFungibleToken__mint(to, tokenId); -} - -export circuit _burn(tokenId: Uint<128>): [] { - return NonFungibleToken__burn(tokenId); -} - -export circuit _transfer( - from: Either, - to: Either, - tokenId: Uint<128> -): [] { - return NonFungibleToken__transfer(from, to, tokenId); -} - -export circuit _setTokenURI(tokenId: Uint<128>, tokenURI: Opaque<"string">): [] { - return NonFungibleToken__setTokenURI(tokenId, tokenURI); -} - -export circuit _unsafeTransferFrom( - from: Either, - to: Either, - tokenId: Uint<128> -): [] { - return NonFungibleToken__unsafeTransferFrom(from, to, tokenId); -} - -export circuit _unsafeTransfer( - from: Either, - to: Either, - tokenId: Uint<128> -): [] { - return NonFungibleToken__unsafeTransfer(from, to, tokenId); -} - -export circuit _unsafeMint( - to: Either, - tokenId: Uint<128> -): [] { - return NonFungibleToken__unsafeMint(to, tokenId); -} \ No newline at end of file diff --git a/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact b/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact deleted file mode 100644 index a8ca7fbb..00000000 --- a/contracts/nonFungibleToken/src/test/mocks/NonFungibleTokenTesting.compact +++ /dev/null @@ -1,679 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.15.0; - -/** - * @module NonFungibleToken - * @description An unshielded Non-Fungible Token library. - * - * @notice One notable difference regarding this implementation and the EIP20 spec - * consists of the token size. Uint<128> is used as the token size because Uint<256> - * cannot be supported. - * This is due to encoding limits on the midnight circuit backend: - * https://github.com/midnightntwrk/compactc/issues/929 - * - * @notice At the moment Midnight does not support contract-to-contract communication, but - * there are ongoing efforts to enable this in the future. Thus, the main circuits of this module - * restrict developers from sending tokens to contracts; however, we provide developers - * the ability to experiment with sending tokens to contracts using the `_unsafe` - * transfer methods. Once contract-to-contract communication is available we will follow the - * deprecation plan outlined below: - * - * Initial Minor Version Change: - * - * - Mark _unsafeTransfer as deprecated and emit a warning if possible. - * - Keep its implementation intact so existing callers continue to work. - * - * Later Major Version Change: - * - * - Drop _unsafeTransfer and remove `isContract` guard from `transfer`. - * - By this point, anyone using _unsafeTransfer should have migrated to the now C2C-capable `transfer`. - * - * @notice Missing Features and Improvements: - * - * - Uint256 token IDs - * - Transfer/Approval events - * - safeTransfer functions - * - _baseURI() support - * - An ERC165-like interface - */ - -module NonFungibleTokenTesting { - import CompactStandardLibrary; - import "../../node_modules/@openzeppelin-midnight/utils/src/Utils" prefix Utils_; - import "../../node_modules/@openzeppelin-midnight/utils/src/Initializable" prefix Initializable_; - - /// Public state - export sealed ledger _name: Opaque<"string">; - export sealed ledger _symbol: Opaque<"string">; - export ledger _owners: Map, Either>; - export ledger _balances: Map, Uint<128>>; - export ledger _tokenApprovals: Map, Either>; - export ledger _operatorApprovals: Map, Map, Boolean>>; - export ledger _tokenURIs: Map, Opaque<"string">>; - - /** - * @description Initializes the contract by setting the name and symbol. - * - * Requirements: - * - The contract must not have been initialized. - * - * @param {Opaque<"string">} name_ - The name of the token. - * @param {Opaque<"string">} symbol_ - The symbol of the token. - * @return {[]} - None. - */ - export circuit initialize( - name_: Opaque<"string">, - symbol_: Opaque<"string"> - ): [] { - Initializable_assertNotInitialized(); - Initializable_initialize(); - _name = name_; - _symbol = symbol_; - } - - /** - * @description Returns the number of tokens in `owner`'s account. - * - * Requirements: - * - The contract must have been initialized. - * - * @param {Either)} owner - The account to query. - * @return {Uint<128>} - The number of tokens in `owner`'s account. - */ - export circuit balanceOf(owner: Either): Uint<128> { - Initializable_assertInitialized(); - if (!_balances.member(owner)) { - return 0; - } - - return _balances.lookup(owner); - } - - /** - * @description Returns the owner of the `tokenId` token. - * - * Requirements: - * - The contract must have been initialized. - * - The `tokenId` must exist. - * - * @param {Uint<128>} tokenId - The identifier for a token. - * @return {Either} - The account that owns the token. - */ - export circuit ownerOf(tokenId: Uint<128>): Either { - Initializable_assertInitialized(); - return _requireOwned(tokenId); - } - - /** - * @description Returns the token name. - * - * Requirements: - * - The contract must have been initialized. - * - * @return {Opaque<"string">} - The token name. - */ - export circuit name(): Opaque<"string"> { - Initializable_assertInitialized(); - return _name; - } - - /** - * @description Returns the symbol of the token. - * - * Requirements: - * - The contract must have been initialized. - * - * @return {Opaque<"string">} - The token symbol. - */ - export circuit symbol(): Opaque<"string"> { - Initializable_assertInitialized(); - return _symbol; - } - - /** - * @description Returns the token URI for the given `tokenId`. Returns the empty - * string if a tokenURI does not exist. - * - * Requirements: - * - The contract must have been initialized. - * - The `tokenId` must exist. - * - * @notice Midnight does not support native strings and string operations - * within the Compact language, e.g. concatenating a base URI + token ID are not possible - * like in other NFT implementations. Therefore, we propose the URI storage - * approach; whereby, NFTs may or may not have unique "base" URIs. - * It's up to the implementation to decide on how to handle this. - * - * @param {Uint<128>} tokenId - The identifier for a token. - * @returns {Opaque<"string">} - the token id's URI. - */ - export circuit tokenURI(tokenId: Uint<128>): Opaque<"string"> { - Initializable_assertInitialized(); - _requireOwned(tokenId); - - if (!_tokenURIs.member(tokenId)) { - return Utils_emptyString(); - } - - return _tokenURIs.lookup(tokenId); - } - - /** - * @description Sets the the URI as `tokenURI` for the given `tokenId`. - * - * Requirements: - * - The contract must have been initialized. - * - The `tokenId` must exist. - * - * @notice The URI for a given NFT is usually set when the NFT is minted. - * - * @param {Uint<128>} tokenId - The identifier of the token. - * @param {Opaque<"string">} tokenURI - The URI of `tokenId`. - * @return {[]} - None. - */ - export circuit _setTokenURI(tokenId: Uint<128>, tokenURI: Opaque<"string">): [] { - Initializable_assertInitialized(); - _requireOwned(tokenId); - - return _tokenURIs.insert(tokenId, tokenURI); - } - - /** - * @description Gives permission to `to` to transfer `tokenId` token to another account. - * The approval is cleared when the token is transferred. - * - * Only a single account can be approved at a time, so approving the zero address clears previous approvals. - * - * Requirements: - * - The contract must have been initialized. - * - The caller must either own the token or be an approved operator. - * - `tokenId` must exist. - * - * @param {Either} to - The account receiving the approval - * @param {Uint<128>} tokenId - The token `to` may be permitted to transfer - * @return {[]} - None. - */ - export circuit approve( - to: Either, - tokenId: Uint<128> - ): [] { - Initializable_assertInitialized(); - const auth = left(own_public_key()); - _approve( - to, - tokenId, - auth - ); - } - - /** - * @description Returns the account approved for `tokenId` token. - * - * Requirements: - * - The contract must have been initialized. - * - `tokenId` must exist. - * - * @param {Uint<128>} tokenId - The token an account may be approved to manage - * @return {Either} Operator- The account approved to manage the token - */ - export circuit getApproved(tokenId: Uint<128>): Either { - Initializable_assertInitialized(); - _requireOwned(tokenId); - - return _getApproved(tokenId); - } - - /** - * @description Approve or remove `operator` as an operator for the caller. - * Operators can call {transferFrom} for any token owned by the caller. - * - * Requirements: - * - The contract must have been initialized. - * - The `operator` cannot be the address zero. - * - * @param {Either} operator - An operator to manage the caller's tokens - * @param {Boolean} approved - A boolean determining if `operator` may manage all tokens of the caller - * @return {[]} - None. - */ - export circuit setApprovalForAll( - operator: Either, - approved: Boolean - ): [] { - Initializable_assertInitialized(); - const owner = left(own_public_key()); - _setApprovalForAll( - owner, - operator, - approved - ); - } - - /** - * @description Returns if the `operator` is allowed to manage all of the assets of `owner`. - * - * Requirements: - * - The contract must have been initialized. - * - * @param {Either} owner - The owner of a token - * @param {Either} operator - An account that may operate on `owner`'s tokens - * @return {Boolean} - A boolean determining if `operator` is allowed to manage all of the tokens of `owner` - */ - export circuit isApprovedForAll( - owner: Either, - operator: Either - ): Boolean { - Initializable_assertInitialized(); - if (_operatorApprovals.member(owner) && _operatorApprovals.lookup(owner).member(operator)) { - return _operatorApprovals.lookup(owner).lookup(operator); - } else { - return false; - } - } - - /** - * @description Transfers `tokenId` token from `from` to `to`. - * - * Requirements: - * - The contract must have been initialized. - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `to` cannot be ContractAddress. - * - `tokenId` token must be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - * - * @param {Either} from - The source account from which the token is being transfered - * @param {Either} to - The target account to transfer token to - * @param {Uint<128>} tokenId - The token being transfered - * @return {[]} - None. - */ - export circuit transferFrom( - from: Either, - to: Either, - tokenId: Uint<128> - ): [] { - Initializable_assertInitialized(); - assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; - - _unsafeTransferFrom(from, to, tokenId); - } - - /** - * @description Transfers `tokenId` token from `from` to `to`. It does NOT check if the recipient is a ContractAddress. - * - * Requirements: - * - The contract must have been initialized. - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - * - * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts - * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the - * ContractAddress - * - * @param {Either} from - The source account from which the token is being transfered - * @param {Either} to - The target account to transfer token to - * @param {Uint<128>} tokenId - The token being transfered - * @return {[]} - None. - */ - export circuit _unsafeTransferFrom( - from: Either, - to: Either, - tokenId: Uint<128> - ): [] { - Initializable_assertInitialized(); - assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; - // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists - // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. - const auth = left(own_public_key()); - const previousOwner = _update( - to, - tokenId, - auth - ); - assert previousOwner == from "NonFungibleToken: Incorrect Owner"; - } - - /** - * @description Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist - * - * Requirements: - * - The contract must have been initialized. - * - * @param {Uint<128>} tokenId - The target token of the owner query - * @return {Either} - The owner of the token - */ - export circuit _ownerOf(tokenId: Uint<128>): Either { - Initializable_assertInitialized(); - if (!_owners.member(tokenId)) { - return burn_address(); - } - - return _owners.lookup(tokenId); - } - - /** - * @description Returns the approved address for `tokenId`. Returns the zero address if `tokenId` is not minted. - * - * Requirements: - * - The contract must have been initialized. - * - * @param {Uint<128>} tokenId - The token to query - * @return {Either} - An account approved to spend `tokenId` - */ - export circuit _getApproved(tokenId: Uint<128>): Either { - Initializable_assertInitialized(); - if (!_tokenApprovals.member(tokenId)) { - return burn_address(); - } - return _tokenApprovals.lookup(tokenId); - } - - /** - * @description Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in - * particular (ignoring whether it is owned by `owner`). - * - * Requirements: - * - The contract must have been initialized. - * - * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this - * assumption. - * - * @param {Either} owner - Owner of the token - * @param {Either} spender - Account that wishes to spend `tokenId` - * @param {Uint<128>} tokenId - Token to spend - * @return {Boolean} - A boolean determining if `spender` may manage `tokenId` - */ - export circuit _isAuthorized( - owner: Either, - spender: Either, - tokenId: Uint<128> - ): Boolean { - Initializable_assertInitialized(); - return ( - !Utils_isKeyOrAddressZero(spender) && - (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender) - ); - } - - /** - * @description Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. - * - * Requirements: - * - The contract must have been initialized. - * - `spender` has approval from `owner` for `tokenId` OR `spender` has approval to manage all of `owner`'s assets. - * - * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this - * assumption. - * - * @param {Either} owner - Owner of the token - * @param {Either} spender - Account operating on `tokenId` - * @param {Uint<128>} tokenId - The token to spend - * @return {[]} - None. - */ - export circuit _checkAuthorized( - owner: Either, - spender: Either, - tokenId: Uint<128> - ): [] { - Initializable_assertInitialized(); - if (!_isAuthorized(owner, spender, tokenId)) { - assert !Utils_isKeyOrAddressZero(owner) "NonFungibleToken: Nonexistent Token"; - assert false "NonFungibleToken: Insufficient Approval"; - } - } - - /** - * @description Mints `tokenId` and transfers it to `to`. - * - * Requirements: - * - The contract must have been initialized. - * - `tokenId` must not exist. - * - `to` cannot be the zero address. - * - `to` cannot be ContractAddress. - * - * @param {Either} to - The account receiving `tokenId` - * @param {Uint<128>} tokenId - The token to transfer - * @return {[]} - None. - */ - export circuit _mint( - to: Either, - tokenId: Uint<128> - ): [] { - Initializable_assertInitialized(); - assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; - - _unsafeMint(to, tokenId); - } - - /** - * @description Mints `tokenId` and transfers it to `to`. It does NOT check if the recipient is a ContractAddress. - * - * Requirements: - * - The contract must have been initialized. - * - `tokenId` must not exist. - * - `to` cannot be the zero address. - * - * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts - * may result in a permanent loss of the token. - * - * @param {Either} to - The account receiving `tokenId` - * @param {Uint<128>} tokenId - The token to transfer - * @return {[]} - None. - */ - export circuit _unsafeMint( - to: Either, - tokenId: Uint<128> - ): [] { - Initializable_assertInitialized(); - assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; - - const previousOwner = _update(to, tokenId, burn_address()); - - assert Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Invalid Sender"; - } - - /** - * @description Destroys `tokenId`. - * The approval is cleared when the token is burned. - * This circuit does not check if the sender is authorized to operate on the token. - * - * Requirements: - * - The contract must have been initialized. - * - `tokenId` must exist. - * - * @param {Uint<128>} tokenId - The token to burn - * @return {[]} - None. - */ - export circuit _burn(tokenId: Uint<128>): [] { - Initializable_assertInitialized(); - const previousOwner = _update(burn_address(), tokenId, burn_address()); - assert !Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Invalid Sender"; - } - - /** - * @description Transfers `tokenId` from `from` to `to`. - * As opposed to {transferFrom}, this imposes no restrictions on own_public_key(). - * - * Requirements: - * - The contract must have been initialized. - * - `to` cannot be the zero address. - * - `to` cannot be ContractAddress. - * - `tokenId` token must be owned by `from`. - * - * @param {Either} from - The source account of the token transfer - * @param {Either} to - The target account of the token transfer - * @param {Uint<128>} tokenId - The token to transfer - * @return {[]} - None. - */ - export circuit _transfer( - from: Either, - to: Either, - tokenId: Uint<128> - ): [] { - Initializable_assertInitialized(); - assert !Utils_isContractAddress(to) "NonFungibleToken: Unsafe Transfer"; - - _unsafeTransfer(from, to, tokenId); - } - - /** - * @description Transfers `tokenId` from `from` to `to`. - * As opposed to {_unsafeTransferFrom}, this imposes no restrictions on own_public_key(). - * It does NOT check if the recipient is a ContractAddress. - * - * Requirements: - * - The contract must have been initialized. - * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. - * - * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts - * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the - * ContractAddress - * - * @param {Either} from - The source account of the token transfer - * @param {Either} to - The target account of the token transfer - * @param {Uint<128>} tokenId - The token to transfer - * @return {[]} - None. - */ - export circuit _unsafeTransfer( - from: Either, - to: Either, - tokenId: Uint<128> - ): [] { - Initializable_assertInitialized(); - assert !Utils_isKeyOrAddressZero(to) "NonFungibleToken: Invalid Receiver"; - - const previousOwner = _update(to, tokenId, burn_address()); - - assert !Utils_isKeyOrAddressZero(previousOwner) "NonFungibleToken: Nonexistent Token"; - assert previousOwner == from "NonFungibleToken: Incorrect Owner"; - } - - /** - * @description Approve `to` to operate on `tokenId` - * - * Requirements: - * - The contract must have been initialized. - * - If `auth` is non 0, then this function will check that `auth` is either the owner of the token, - * or approved to operate on the token (by the owner). - * - * @param {Either} to - The target account to approve - * @param {Uint<128>} tokenId - The token to approve - * @param {Either} auth - An account authorized to operate on all tokens held by the owner the token - * @return {[]} - None. - */ - export circuit _approve( - to: Either, - tokenId: Uint<128>, - auth: Either - ): [] { - Initializable_assertInitialized(); - if (!Utils_isKeyOrAddressZero(auth)) { - const owner = _requireOwned(tokenId); - - // We do not use _isAuthorized because single-token approvals should not be able to call approve - assert (owner == auth || isApprovedForAll(owner, auth)) "NonFungibleToken: Invalid Approver"; - } - - _tokenApprovals.insert(tokenId, to); - } - - /** - * @description Approve `operator` to operate on all of `owner` tokens - * - * Requirements: - * - The contract must have been initialized. - * - `operator` can't be the address zero. - * - * @param {Either} owner - Owner of a token - * @param {Either} operator - The account to approve - * @param {Boolean} approved - A boolean determining if `operator` may operate on all of `owner` tokens - * @return {[]} - None. - */ - export circuit _setApprovalForAll( - owner: Either, - operator: Either, - approved: Boolean - ): [] { - Initializable_assertInitialized(); - assert !Utils_isKeyOrAddressZero(operator) "NonFungibleToken: Invalid Operator"; - - if (!_operatorApprovals.member(owner)) { - _operatorApprovals.insert( - owner, - default, Boolean>> - ); - } - - _operatorApprovals.lookup(owner).insert(operator, approved); - } - - /** - * @description Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). - * Returns the owner. - * - * Requirements: - * - The contract must have been initialized. - * - `tokenId` must exist. - * - * @param {Uint<128>} tokenId - The token that should be owned - * @return {Either} - The owner of `tokenId` - */ - export circuit _requireOwned(tokenId: Uint<128>): Either { - Initializable_assertInitialized(); - const owner = _ownerOf(tokenId); - - assert !Utils_isKeyOrAddressZero(owner) "NonFungibleToken: Nonexistent Token"; - return owner; - } - - /** - * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner - * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. - * - * Requirements: - * - The contract must have been initialized. - * - If `auth` is non 0, then this function will check that `auth` is either the owner of the token, - * or approved to operate on the token (by the owner). - * - * @param {Either} to - The intended recipient of the token transfer - * @param {Uint<128>} tokenId - The token being transfered - * @param {Either} auth - An account authorized to transfer the token - * @return {Either} - Owner of the token before it was transfered - */ - export circuit _update( - to: Either, - tokenId: Uint<128>, - auth: Either - ): Either { - Initializable_assertInitialized(); - const from = _ownerOf(tokenId); - - // Perform (optional) operator check - if (!Utils_isKeyOrAddressZero(auth)) { - _checkAuthorized(from, auth, tokenId); - } - - // Execute the update - if (!Utils_isKeyOrAddressZero(from)) { - // Clear approval. No need to re-authorize - _approve(burn_address(), tokenId, burn_address()); - const newBalance = _balances.lookup(from) - 1 as Uint<128>; - _balances.insert(from, newBalance); - } - - if (!Utils_isKeyOrAddressZero(to)) { - if (!_balances.member(to)) { - _balances.insert(to, 0); - } - const newBalance = _balances.lookup(to) + 1 as Uint<128>; - _balances.insert(to, newBalance); - } - - _owners.insert(tokenId, to); - - return from; - } -} diff --git a/contracts/nonFungibleToken/src/test/simulators/UninitializedNonFungibleTokenSimulator.ts b/contracts/nonFungibleToken/src/test/simulators/UninitializedNonFungibleTokenSimulator.ts deleted file mode 100644 index c0a25152..00000000 --- a/contracts/nonFungibleToken/src/test/simulators/UninitializedNonFungibleTokenSimulator.ts +++ /dev/null @@ -1,635 +0,0 @@ -import { - type CircuitContext, - type CoinPublicKey, - type ContractState, - QueryContext, - constructorContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; -import { - type ContractAddress, - type Either, - type Ledger, - Contract as MockUninitializedNonFungibleToken, - type ZswapCoinPublicKey, - ledger, -} from '../../artifacts/MockUninitializedNonFungibleToken/contract/index.cjs'; // Combined imports -import { - type NonFungibleTokenPrivateState, - NonFungibleTokenWitnesses, -} from '../../witnesses/NonFungibleTokenWitnesses.js'; -import type { IContractSimulator } from '../types/test.js'; - -/** - * @description A simulator implementation of an NonFungibleToken contract for testing purposes. - * @template P - The private state type, fixed to NonFungibleTokenPrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. - */ -export class UninitializedNonFungibleTokenSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockUninitializedNonFungibleToken; - - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor() { - this.contract = - new MockUninitializedNonFungibleToken( - NonFungibleTokenWitnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type NonFungibleTokenPrivateState. - */ - public getCurrentPrivateState(): NonFungibleTokenPrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; - } - - /** - * @description Returns the token name. - * @returns The token name. - */ - public name(): string { - return this.contract.impureCircuits.name(this.circuitContext).result; - } - - /** - * @description Returns the symbol of the token. - * @returns The token name. - */ - public symbol(): string { - return this.contract.impureCircuits.symbol(this.circuitContext).result; - } - - /** - * @description Returns the number of tokens in `account`'s account. - * @param account The public key to query. - * @return The number of tokens in `account`'s account. - */ - public balanceOf( - account: Either, - ): bigint { - return this.contract.impureCircuits.balanceOf(this.circuitContext, account) - .result; - } - - /** - * @description Returns the owner of the `tokenId` token. - * @param tokenId The identifier for a token. - * @return The public key that owns the token. - */ - public ownerOf(tokenId: bigint): Either { - return this.contract.impureCircuits.ownerOf(this.circuitContext, tokenId) - .result; - } - - /** - * @description Returns the token URI for the given `tokenId`. - * @notice Since Midnight does not support native strings and string operations - * within the Compact language, concatenating a base URI + token ID is not possible - * like in other NFT implementations. Therefore, we propose the URI storage - * approach; whereby, NFTs may or may not have unique "base" URIs. - * It's up to the implementation to decide on how to handle this. - * @param tokenId The identifier for a token. - * @returns The token id's URI. - */ - public tokenURI(tokenId: bigint): string { - return this.contract.impureCircuits.tokenURI(this.circuitContext, tokenId) - .result; - } - - /** - * @description Gives permission to `to` to transfer `tokenId` token to another account. - * The approval is cleared when the token is transferred. - * - * Only a single account can be approved at a time, so approving the zero address clears previous approvals. - * - * Requirements: - * - * - The caller must own the token or be an approved operator. - * - `tokenId` must exist. - * - * @param to The account receiving the approval - * @param tokenId The token `to` may be permitted to transfer - * @return None. - */ - public approve( - to: Either, - tokenId: bigint, - sender?: CoinPublicKey, - ) { - const res = this.contract.impureCircuits.approve( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - to, - tokenId, - ); - - this.circuitContext = res.context; - } - - /** - * @description Returns the account approved for `tokenId` token. - * @param tokenId The token an account may be approved to manage - * @return The account approved to manage the token - */ - public getApproved( - tokenId: bigint, - ): Either { - return this.contract.impureCircuits.getApproved( - this.circuitContext, - tokenId, - ).result; - } - - /** - * @description Approve or remove `operator` as an operator for the caller. - * Operators can call {transferFrom} for any token owned by the caller. - * - * Requirements: - * - * - The `operator` cannot be the address zero. - * - * @param operator An operator to manage the caller's tokens - * @param approved A boolean determining if `operator` may manage all tokens of the caller - * @return None. - */ - public setApprovalForAll( - operator: Either, - approved: boolean, - sender?: CoinPublicKey, - ) { - const res = this.contract.impureCircuits.setApprovalForAll( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - operator, - approved, - ); - - this.circuitContext = res.context; - } - - /** - * @description Returns if the `operator` is allowed to manage all of the assets of `owner`. - * - * @param owner The owner of a token - * @param operator An account that may operate on `owner`'s tokens - * @return A boolean determining if `operator` is allowed to manage all of the tokens of `owner` - */ - public isApprovedForAll( - owner: Either, - operator: Either, - ): boolean { - return this.contract.impureCircuits.isApprovedForAll( - this.circuitContext, - owner, - operator, - ).result; - } - - /** - * @description Transfers `tokenId` token from `from` to `to`. - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - * - * @param {Either} from - The source account from which the token is being transfered - * @param {Either} to - The target account to transfer token to - * @param {TokenId} tokenId - The token being transfered - * @return {[]} - None. - */ - public transferFrom( - from: Either, - to: Either, - tokenId: bigint, - sender?: CoinPublicKey, - ) { - const res = this.contract.impureCircuits.transferFrom( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, - to, - tokenId, - ); - - this.circuitContext = res.context; - } - - /** - * @description Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). - * Returns the owner. - * - * Overrides to ownership logic should be done to {_ownerOf}. - * - * @param tokenId The token that should be owned - * @return The owner of `tokenId` - */ - public _requireOwned( - tokenId: bigint, - ): Either { - return this.contract.impureCircuits._requireOwned( - this.circuitContext, - tokenId, - ).result; - } - - /** - * @description Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist - * - * @param tokenId The target token of the owner query - * @return The owner of the token - */ - public _ownerOf( - tokenId: bigint, - ): Either { - return this.contract.impureCircuits._ownerOf(this.circuitContext, tokenId) - .result; - } - - /** - * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner - * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. - * - * The `auth` argument is optional. If the value passed is non 0, then this function will check that - * `auth` is either the owner of the token, or approved to operate on the token (by the owner). - * - * @param to The intended recipient of the token transfer - * @param tokenId The token being transfered - * @param auth An account authorized to transfer the token - * @return Owner of the token before it was transfered - */ - public _update( - to: Either, - tokenId: bigint, - auth: Either, - ): Either { - const res = this.contract.impureCircuits._update( - this.circuitContext, - to, - tokenId, - auth, - ); - - this.circuitContext = res.context; - return res.result; - } - - /** - * @description Approve `to` to operate on `tokenId` - * - * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is - * either the owner of the token, or approved to operate on all tokens held by this owner. - * - * @param to The target account to approve - * @param tokenId The token to approve - * @param auth An account authorized to operate on all tokens held by the owner the token - * @return None. - */ - public _approve( - to: Either, - tokenId: bigint, - auth: Either, - ) { - this.circuitContext = this.contract.impureCircuits._approve( - this.circuitContext, - to, - tokenId, - auth, - ).context; - } - - /** - * @description Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. - * Reverts if: - * - `spender` does not have approval from `owner` for `tokenId`. - * - `spender` does not have approval to manage all of `owner`'s assets. - * - * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this - * assumption. - * - * @param owner Owner of the token - * @param spender Account operating on `tokenId` - * @param tokenId The token to spend - * @return None. - */ - public _checkAuthorized( - owner: Either, - spender: Either, - tokenId: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._checkAuthorized( - this.circuitContext, - owner, - spender, - tokenId, - ).context; - } - - /** - * @description Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in - * particular (ignoring whether it is owned by `owner`). - * - * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this - * assumption. - * - * @param owner Owner of the token - * @param spender Account that wishes to spend `tokenId` - * @param tokenId Token to spend - * @return A boolean determining if `spender` may manage `tokenId` - */ - public _isAuthorized( - owner: Either, - spender: Either, - tokenId: bigint, - ): boolean { - return this.contract.impureCircuits._isAuthorized( - this.circuitContext, - owner, - spender, - tokenId, - ).result; - } - - /** - * @description Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. - * - * @param tokenId The token to query - * @return An account approved to spend `tokenId` - */ - public _getApproved( - tokenId: bigint, - ): Either { - return this.contract.impureCircuits._getApproved( - this.circuitContext, - tokenId, - ).result; - } - - /** - * @description Approve `operator` to operate on all of `owner` tokens - * - * Requirements: - * - operator can't be the address zero. - * - * @param owner Owner of a token - * @param operator The account to approve - * @param approved A boolean determining if `operator` may operate on all of `owner` tokens - * @return None. - */ - public _setApprovalForAll( - owner: Either, - operator: Either, - approved: boolean, - ) { - this.circuitContext = this.contract.impureCircuits._setApprovalForAll( - this.circuitContext, - owner, - operator, - approved, - ).context; - } - - /** - * @description Mints `tokenId` and transfers it to `to`. - * - * Requirements: - * - * - `tokenId` must not exist. - * - `to` cannot be the zero address. - * - * @param to The account receiving `tokenId` - * @param tokenId The token to transfer - * @return None. - */ - public _mint( - to: Either, - tokenId: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._mint( - this.circuitContext, - to, - tokenId, - ).context; - } - - /** - * @description Destroys `tokenId`. - * The approval is cleared when the token is burned. - * This is an internal function that does not check if the sender is authorized to operate on the token. - * - * Requirements: - * - * - `tokenId` must exist. - * - * @param tokenId The token to burn - * @return None. - */ - public _burn(tokenId: bigint) { - this.circuitContext = this.contract.impureCircuits._burn( - this.circuitContext, - tokenId, - ).context; - } - - /** - * @description Transfers `tokenId` from `from` to `to`. - * As opposed to {transferFrom}, this imposes no restrictions on own_public_key(). - * - * Requirements: - * - * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. - * - * @param from The source account of the token transfer - * @param to The target account of the token transfer - * @param tokenId The token to transfer - * @return None. - */ - public _transfer( - from: Either, - to: Either, - tokenId: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._transfer( - this.circuitContext, - from, - to, - tokenId, - ).context; - } - - /** - * @description Sets the the URI as `tokenURI` for the given `tokenId`. - * The `tokenId` must exist. - * - * @notice The URI for a given NFT is usually set when the NFT is minted. - * - * @param tokenId The identifier of the token. - * @param tokenURI The URI of `tokenId`. - * @return None - */ - public _setTokenURI(tokenId: bigint, tokenURI: string) { - this.circuitContext = this.contract.impureCircuits._setTokenURI( - this.circuitContext, - tokenId, - tokenURI, - ).context; - } - - /** - * @description Transfers `tokenId` token from `from` to `to`. It does NOT check if the recipient is a ContractAddress. - * - * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts - * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the - * ContractAddress - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - * - * @param {Either} from - The source account from which the token is being transfered - * @param {Either} to - The target account to transfer token to - * @param {TokenId} tokenId - The token being transfered - * @return {[]} - None. - */ - public _unsafeTransferFrom( - from: Either, - to: Either, - tokenId: bigint, - sender?: CoinPublicKey, - ) { - const res = this.contract.impureCircuits._unsafeTransferFrom( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, - to, - tokenId, - ); - - this.circuitContext = res.context; - } - - /** - * @description Transfers `tokenId` from `from` to `to`. - * As opposed to {_unsafeTransferFrom}, this imposes no restrictions on own_public_key(). - * It does NOT check if the recipient is a ContractAddress. - * - * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts - * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the - * ContractAddress - * - * Requirements: - * - * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. - * - * @param {Either} from - The source account of the token transfer - * @param {Either} to - The target account of the token transfer - * @param {TokenId} tokenId - The token to transfer - * @return {[]} - None. - */ - public _unsafeTransfer( - from: Either, - to: Either, - tokenId: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._unsafeTransfer( - this.circuitContext, - from, - to, - tokenId, - ).context; - } - - /** - * @description Mints `tokenId` and transfers it to `to`. It does NOT check if the recipient is a ContractAddress. - * - * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts - * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the - * ContractAddress - * - * Requirements: - * - * - `tokenId` must not exist. - * - `to` cannot be the zero address. - * - * @param {Either} to - The account receiving `tokenId` - * @param {TokenId} tokenId - The token to transfer - * @return {[]} - None. - */ - public _unsafeMint( - to: Either, - tokenId: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._unsafeMint( - this.circuitContext, - to, - tokenId, - ).context; - } -} From 8e5f9dbbc54a948f638642523d69e39b89827dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:44:35 -0400 Subject: [PATCH 248/282] Fix import, add docs to constructor, add condition init, remove _update --- .../test/mocks/MockNonFungibleToken.compact | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact index ff75aa7d..b0b5aa4b 100644 --- a/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact @@ -2,15 +2,25 @@ pragma language_version >= 0.15.0; import CompactStandardLibrary; -import "NonFungibleTokenTesting" prefix NonFungibleToken_; +import "../../NonFungibleToken" prefix NonFungibleToken_; export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; +/** + * @description `init` is a param for testing. + * If `init` is true, initialize the contract with the + * _name`, `_symbol`, and `_decimals`. + * Otherwise, the contract will not initialize and we can test + * the contract when it is not initialized properly. +*/ constructor( _name: Opaque<"string">, - _symbol: Opaque<"string"> + _symbol: Opaque<"string">, + init: Boolean ) { - NonFungibleToken_initialize(_name, _symbol); + if (init) { + NonFungibleToken_initialize(_name, _symbol); + } } export circuit name(): Opaque<"string"> { @@ -74,14 +84,6 @@ export circuit _ownerOf(tokenId: Uint<128>): Either, - tokenId: Uint<128>, - auth: Either -): Either { - return NonFungibleToken__update(to, tokenId, auth); -} - export circuit _approve( to: Either, tokenId: Uint<128>, From f218a6adb95e4128889b00eef1ebf88d2bf6b05e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:45:10 -0400 Subject: [PATCH 249/282] Update constructor, remove _update, --- .../simulators/NonFungibleTokenSimulator.ts | 31 ++----------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts b/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts index e0b730a7..dd5e2146 100644 --- a/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts +++ b/contracts/nonFungibleToken/src/test/simulators/NonFungibleTokenSimulator.ts @@ -41,7 +41,7 @@ export class NonFungibleTokenSimulator /** * @description Initializes the mock contract. */ - constructor(name: string, symbol: string) { + constructor(name: string, symbol: string, init: boolean) { this.contract = new MockNonFungibleToken( NonFungibleTokenWitnesses, ); @@ -53,6 +53,7 @@ export class NonFungibleTokenSimulator constructorContext({}, '0'.repeat(64)), name, symbol, + init, ); this.circuitContext = { currentPrivateState, @@ -307,34 +308,6 @@ export class NonFungibleTokenSimulator .result; } - /** - * @description Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner - * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. - * - * The `auth` argument is optional. If the value passed is non 0, then this function will check that - * `auth` is either the owner of the token, or approved to operate on the token (by the owner). - * - * @param to The intended recipient of the token transfer - * @param tokenId The token being transfered - * @param auth An account authorized to transfer the token - * @return Owner of the token before it was transfered - */ - public _update( - to: Either, - tokenId: bigint, - auth: Either, - ): Either { - const res = this.contract.impureCircuits._update( - this.circuitContext, - to, - tokenId, - auth, - ); - - this.circuitContext = res.context; - return res.result; - } - /** * @description Approve `to` to operate on `tokenId` * From 7fca850d3111af67fab33059a4b78484b7f7d9d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:45:32 -0400 Subject: [PATCH 250/282] Fmt docs --- .../src/test/mocks/MockNonFungibleToken.compact | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact index b0b5aa4b..29a91a1e 100644 --- a/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/test/mocks/MockNonFungibleToken.compact @@ -8,10 +8,9 @@ export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; /** * @description `init` is a param for testing. - * If `init` is true, initialize the contract with the - * _name`, `_symbol`, and `_decimals`. - * Otherwise, the contract will not initialize and we can test - * the contract when it is not initialized properly. + * If `init` is true, initialize the contract with `_name` and `_symbol`. + * Otherwise, the contract will not initialize and we can test the + * contract when it is not initialized properly. */ constructor( _name: Opaque<"string">, From f55949c7b5fc1fa73c53ce43e3a53b1884acef24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:46:01 -0400 Subject: [PATCH 251/282] Add toHexPadded method --- .../src/test/utils/address.ts | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 contracts/nonFungibleToken/src/test/utils/address.ts diff --git a/contracts/nonFungibleToken/src/test/utils/address.ts b/contracts/nonFungibleToken/src/test/utils/address.ts new file mode 100644 index 00000000..af4ed548 --- /dev/null +++ b/contracts/nonFungibleToken/src/test/utils/address.ts @@ -0,0 +1,81 @@ +import { + convert_bigint_to_Uint8Array, + encodeCoinPublicKey, +} from '@midnight-ntwrk/compact-runtime'; +import { encodeContractAddress } from '@midnight-ntwrk/ledger'; +import type * as Compact from '../../artifacts/MockNonFungibleToken/contract/index.cjs'; + +const PREFIX_ADDRESS = '0200'; + +/** + * @description Converts an ASCII string to its hexadecimal representation, + * left-padded with zeros to a specified length. Useful for generating + * fixed-size hex strings for encoding. + * @param str ASCII string to convert. + * @param len Total desired length of the resulting hex string. Defaults to 64. + * @returns Hexadecimal string representation of `str`, padded to `length` characters. + */ +export const toHexPadded = (str: string, len = 64) => + Buffer.from(str, 'ascii').toString('hex').padStart(len, '0'); + +/** + * @description Generates ZswapCoinPublicKey from `str` for testing purposes. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { + const toHex = Buffer.from(str, 'ascii').toString('hex'); + return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; +}; + +/** + * @description Generates ContractAddress from `str` for testing purposes. + * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToAddress = (str: string): Compact.ContractAddress => { + const toHex = Buffer.from(str, 'ascii').toString('hex'); + const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); + return { bytes: encodeContractAddress(fullAddress) }; +}; + +/** + * @description Generates an Either object for ZswapCoinPublicKey for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ZswapCoinPublicKey. + */ +export const createEitherTestUser = (str: string) => { + return { + is_left: true, + left: encodeToPK(str), + right: encodeToAddress(''), + }; +}; + +/** + * @description Generates an Either object for ContractAddress for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ContractAddress. + */ +export const createEitherTestContractAddress = (str: string) => { + return { + is_left: false, + left: encodeToPK(''), + right: encodeToAddress(str), + }; +}; + +export const ZERO_KEY = { + is_left: true, + left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, + right: encodeToAddress(''), +}; + +export const ZERO_ADDRESS = { + is_left: false, + left: encodeToPK(''), + right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, +}; From 54ca72f014cbde4c4c0bf84c87c24ba546da4991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:46:14 -0400 Subject: [PATCH 252/282] Remove duplicate code --- contracts/utils/src/test/mocks/MockUtils.compact | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/contracts/utils/src/test/mocks/MockUtils.compact b/contracts/utils/src/test/mocks/MockUtils.compact index 2f481ddc..eaeb3d18 100644 --- a/contracts/utils/src/test/mocks/MockUtils.compact +++ b/contracts/utils/src/test/mocks/MockUtils.compact @@ -28,18 +28,3 @@ export pure circuit isContractAddress(keyOrAddress: Either { return Utils_emptyString(); } - -export pure circuit isKeyOrAddressEqual( - keyOrAddress: Either, - other: Either -): Boolean { - return Utils_isKeyOrAddressEqual(keyOrAddress, other); -} - -export pure circuit isKeyZero(key: ZswapCoinPublicKey): Boolean { - return Utils_isKeyZero(key); -} - -export pure circuit isContractAddress(keyOrAddress: Either): Boolean { - return Utils_isContractAddress(keyOrAddress); -} From 373af66be3c845c38d0bee90923f505229c3da38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 26 Jun 2025 02:19:19 -0400 Subject: [PATCH 253/282] fix rebase issues --- compact/package.json | 3 + contracts/fungibleToken/package.json | 3 + .../test/simulators/FungibleTokenSimulator.ts | 4 +- contracts/fungibleToken/tsconfig.json | 8 +-- contracts/nonFungibleToken/package.json | 36 +++++++++++ .../src/NonFungibleToken.compact | 2 +- .../nonFungibleToken/tsconfig.build.json | 5 ++ contracts/nonFungibleToken/tsconfig.json | 21 +++++++ contracts/utils/package.json | 6 +- contracts/utils/src/Utils.compact | 7 --- contracts/utils/src/test/utils.test.ts | 59 +------------------ contracts/utils/src/test/utils/address.ts | 22 +++---- package.json | 2 +- yarn.lock | 37 ++++++------ 14 files changed, 111 insertions(+), 104 deletions(-) create mode 100644 contracts/nonFungibleToken/package.json create mode 100644 contracts/nonFungibleToken/tsconfig.build.json create mode 100644 contracts/nonFungibleToken/tsconfig.json diff --git a/compact/package.json b/compact/package.json index 8e4541ed..786f6b0c 100644 --- a/compact/package.json +++ b/compact/package.json @@ -22,6 +22,9 @@ "scripts": { "build": "tsc -p .", "types": "tsc -p tsconfig.json --noEmit", + "fmt-and-lint": "biome check . --changed", + "fmt-and-lint:fix": "biome check . --changed --fix", + "fmt-and-lint:ci": "biome ci --changed --no-errors-on-unmatched", "clean": "git clean -fXd" }, "devDependencies": { diff --git a/contracts/fungibleToken/package.json b/contracts/fungibleToken/package.json index 68b33631..335abf5d 100644 --- a/contracts/fungibleToken/package.json +++ b/contracts/fungibleToken/package.json @@ -18,6 +18,9 @@ "build": "compact-builder && tsc", "test": "vitest run", "types": "tsc -p tsconfig.json --noEmit", + "fmt-and-lint": "biome check . --changed", + "fmt-and-lint:fix": "biome check . --changed --fix", + "fmt-and-lint:ci": "biome ci --changed --no-errors-on-unmatched", "clean": "git clean -fXd" }, "dependencies": { diff --git a/contracts/fungibleToken/src/test/simulators/FungibleTokenSimulator.ts b/contracts/fungibleToken/src/test/simulators/FungibleTokenSimulator.ts index fc898583..87ecba0b 100644 --- a/contracts/fungibleToken/src/test/simulators/FungibleTokenSimulator.ts +++ b/contracts/fungibleToken/src/test/simulators/FungibleTokenSimulator.ts @@ -18,8 +18,8 @@ import { import { type FungibleTokenPrivateState, FungibleTokenWitnesses, -} from '../../witnesses/FungibleTokenWitnesses'; -import type { IContractSimulator } from '../types/test'; +} from '../../witnesses/FungibleTokenWitnesses.js'; +import type { IContractSimulator } from '../types/test.js'; /** * @description A simulator implementation of a FungibleToken contract for testing purposes. diff --git a/contracts/fungibleToken/tsconfig.json b/contracts/fungibleToken/tsconfig.json index 3e90b0a9..d6c626dc 100644 --- a/contracts/fungibleToken/tsconfig.json +++ b/contracts/fungibleToken/tsconfig.json @@ -4,10 +4,10 @@ "rootDir": "src", "outDir": "dist", "declaration": true, - "lib": ["ESNext"], + "lib": ["ES2022"], "target": "ES2022", - "module": "ESNext", - "moduleResolution": "node", + "module": "nodenext", + "moduleResolution": "nodenext", "allowJs": true, "forceConsistentCasingInFileNames": true, "noImplicitAny": true, @@ -18,4 +18,4 @@ "esModuleInterop": true, "skipLibCheck": true } -} +} \ No newline at end of file diff --git a/contracts/nonFungibleToken/package.json b/contracts/nonFungibleToken/package.json new file mode 100644 index 00000000..c0735a42 --- /dev/null +++ b/contracts/nonFungibleToken/package.json @@ -0,0 +1,36 @@ +{ + "name": "@openzeppelin-midnight/non-fungible-token", + "private": true, + "type": "module", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "scripts": { + "compact": "compact-compiler", + "build": "compact-builder && tsc", + "test": "vitest run", + "types": "tsc -p tsconfig.json --noEmit", + "fmt-and-lint": "biome check . --changed", + "fmt-and-lint:fix": "biome check . --changed --fix", + "fmt-and-lint:ci": "biome ci --changed --no-errors-on-unmatched", + "clean": "git clean -fXd" + }, + "dependencies": { + "@openzeppelin-midnight/compact": "workspace:^" + }, + "devDependencies": { + "@biomejs/biome": "1.9.4", + "@types/node": "22.14.0", + "ts-node": "^10.9.2", + "typescript": "^5.2.2", + "vitest": "^3.1.3" + } +} diff --git a/contracts/nonFungibleToken/src/NonFungibleToken.compact b/contracts/nonFungibleToken/src/NonFungibleToken.compact index 88bab4d9..871bda25 100644 --- a/contracts/nonFungibleToken/src/NonFungibleToken.compact +++ b/contracts/nonFungibleToken/src/NonFungibleToken.compact @@ -763,4 +763,4 @@ module NonFungibleToken { assert !Utils_isKeyOrAddressZero(owner) "NonFungibleToken: Nonexistent Token"; return owner; } -} \ No newline at end of file +} diff --git a/contracts/nonFungibleToken/tsconfig.build.json b/contracts/nonFungibleToken/tsconfig.build.json new file mode 100644 index 00000000..f1132509 --- /dev/null +++ b/contracts/nonFungibleToken/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["src/test/**/*.ts"], + "compilerOptions": {} +} diff --git a/contracts/nonFungibleToken/tsconfig.json b/contracts/nonFungibleToken/tsconfig.json new file mode 100644 index 00000000..d6c626dc --- /dev/null +++ b/contracts/nonFungibleToken/tsconfig.json @@ -0,0 +1,21 @@ +{ + "include": ["src/**/*.ts"], + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "lib": ["ES2022"], + "target": "ES2022", + "module": "nodenext", + "moduleResolution": "nodenext", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": true, + "strict": true, + "isolatedModules": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true + } +} \ No newline at end of file diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 37c54380..5408a32e 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -18,12 +18,16 @@ "build": "compact-builder && tsc", "test": "vitest run", "types": "tsc -p tsconfig.json --noEmit", + "fmt-and-lint": "biome check . --changed", + "fmt-and-lint:fix": "biome check . --changed --fix", + "fmt-and-lint:ci": "biome ci --changed --no-errors-on-unmatched", "clean": "git clean -fXd" }, "dependencies": { - "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" + "@openzeppelin-midnight/compact": "workspace:^" }, "devDependencies": { + "@biomejs/biome": "1.9.4", "@types/node": "22.14.0", "ts-node": "^10.9.2", "typescript": "^5.2.2", diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/src/Utils.compact index 415b5b4f..90ad8986 100644 --- a/contracts/utils/src/Utils.compact +++ b/contracts/utils/src/Utils.compact @@ -38,11 +38,7 @@ module Utils { } /** -<<<<<<< HEAD - * @description Returns whether `keyOrAddress` is equal to `other`. Assumes that a ZswapCoinPublicKey -======= * @description Returns whether `keyOrAddress` is equal to `other`. Assumes that a ZswapCoinPublicKey ->>>>>>> 4f20422 (Update fungible token (#125)) * and a ContractAddress can never be equal * * @param {Either} keyOrAddress - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. @@ -71,7 +67,6 @@ module Utils { export pure circuit isContractAddress(keyOrAddress: Either): Boolean { return !keyOrAddress.is_left; } -<<<<<<< HEAD /** * @description A helper function that returns the empty string: "" @@ -81,6 +76,4 @@ module Utils { export pure circuit emptyString(): Opaque<"string"> { return default>; } -======= ->>>>>>> 4f20422 (Update fungible token (#125)) } diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 39bf24b1..9f618a37 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -8,11 +8,8 @@ const SOME_CONTRACT = contractUtils.createEitherTestContractAddress('SOME_CONTRACT'); const OTHER_CONTRACT = contractUtils.createEitherTestContractAddress('OTHER_CONTRACT'); -<<<<<<< HEAD const EMPTY_STRING = ''; -======= ->>>>>>> 4f20422 (Update fungible token (#125)) let contract: UtilsSimulator; @@ -31,12 +28,6 @@ describe('Utils', () => { expect(contract.isKeyOrAddressZero(Z_SOME_KEY)).toBe(false); expect(contract.isKeyOrAddressZero(SOME_CONTRACT)).toBe(false); }); - - it('should return false for two different address types', () => { - expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, SOME_CONTRACT)).toBe(false); - expect(contract.isKeyOrAddressZero(contractUtils.ZERO_KEY)).toBe(true); - expect(contract.isKeyOrAddressZero(contractUtils.ZERO_ADDRESS)).toBe(true); - }); }); describe('isKeyOrAddressEqual', () => { @@ -101,52 +92,4 @@ describe('Utils', () => { expect(contract.emptyString()).toBe(EMPTY_STRING); }); }); - - describe('isKeyOrAddressEqual', () => { - it('should return true for two matching pubkeys', () => { - expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_SOME_KEY)).toBe(true); - }); - - it('should return true for two matching contract addresses', () => { - expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, SOME_CONTRACT)).toBe( - true, - ); - }); - - it('should return false for two different pubkeys', () => { - expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_OTHER_KEY)).toBe(false); - }); - - it('should return false for two different contract addresses', () => { - expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, OTHER_CONTRACT)).toBe( - false, - ); - }); - - it('should return false for two different address types', () => { - expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, SOME_CONTRACT)).toBe( - false, - ); - }); - }); - - describe('isKeyZero', () => { - it('should return zero for the zero address', () => { - expect(contract.isKeyZero(contractUtils.ZERO_KEY.left)).toBe(true); - }); - - it('should not return zero for nonzero addresses', () => { - expect(contract.isKeyZero(Z_SOME_KEY.left)).toBe(false); - }); - }); - - describe('isContractAddress', () => { - it('should return true if ContractAddress', () => { - expect(contract.isContractAddress(SOME_CONTRACT)).toBe(true); - }); - - it('should return false ZswapCoinPublicKey', () => { - expect(contract.isContractAddress(Z_SOME_KEY)).toBe(false); - }); - }); -}); +}); \ No newline at end of file diff --git a/contracts/utils/src/test/utils/address.ts b/contracts/utils/src/test/utils/address.ts index d4ac78a7..af4ed548 100644 --- a/contracts/utils/src/test/utils/address.ts +++ b/contracts/utils/src/test/utils/address.ts @@ -3,20 +3,20 @@ import { encodeCoinPublicKey, } from '@midnight-ntwrk/compact-runtime'; import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import type * as Compact from '../../artifacts/MockUtils/contract/index.cjs'; +import type * as Compact from '../../artifacts/MockNonFungibleToken/contract/index.cjs'; const PREFIX_ADDRESS = '0200'; -export const pad = (s: string, n: number): Uint8Array => { - const encoder = new TextEncoder(); - const utf8Bytes = encoder.encode(s); - if (n < utf8Bytes.length) { - throw new Error(`The padded length n must be at least ${utf8Bytes.length}`); - } - const paddedArray = new Uint8Array(n); - paddedArray.set(utf8Bytes); - return paddedArray; -}; +/** + * @description Converts an ASCII string to its hexadecimal representation, + * left-padded with zeros to a specified length. Useful for generating + * fixed-size hex strings for encoding. + * @param str ASCII string to convert. + * @param len Total desired length of the resulting hex string. Defaults to 64. + * @returns Hexadecimal string representation of `str`, padded to `length` characters. + */ +export const toHexPadded = (str: string, len = 64) => + Buffer.from(str, 'ascii').toString('hex').padStart(len, '0'); /** * @description Generates ZswapCoinPublicKey from `str` for testing purposes. diff --git a/package.json b/package.json index 3fe48c95..da56058b 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@biomejs/biome": "1.9.4", "@midnight-ntwrk/ledger": "^4.0.0", "@midnight-ntwrk/zswap": "^4.0.0", - "@types/node": "^22", + "@types/node": "22.14.0", "fast-check": "^3.15.0", "ts-node": "^10.9.2", "turbo": "^2.5.1", diff --git a/yarn.lock b/yarn.lock index 5c3e90e9..58e73f6f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -416,10 +416,24 @@ __metadata: languageName: unknown linkType: soft +"@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken": + version: 0.0.0-use.local + resolution: "@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken" + dependencies: + "@biomejs/biome": "npm:1.9.4" + "@openzeppelin-midnight/compact": "workspace:^" + "@types/node": "npm:22.14.0" + ts-node: "npm:^10.9.2" + typescript: "npm:^5.2.2" + vitest: "npm:^3.1.3" + languageName: unknown + linkType: soft + "@openzeppelin-midnight/utils@workspace:contracts/utils": version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" dependencies: + "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:22.14.0" ts-node: "npm:^10.9.2" @@ -654,21 +668,6 @@ __metadata: languageName: node linkType: hard -<<<<<<< HEAD -"@types/node@npm:^22": - version: 22.15.32 - resolution: "@types/node@npm:22.15.32" -======= -"@types/node@npm:^22.14.0": - version: 22.15.33 - resolution: "@types/node@npm:22.15.33" ->>>>>>> 29d6e3f (Update yarn.lock) - dependencies: - undici-types: "npm:~6.21.0" - checksum: 10/5734cbca7fc363f3d6ad191e1be645cc9885d642e9f90688892459f10629cf663d2206e7ed7b255dd476baaa86fb011aa09647e77520958b5993b391f793856f - languageName: node - linkType: hard - "@types/object-inspect@npm:^1.8.1": version: 1.13.0 resolution: "@types/object-inspect@npm:1.13.0" @@ -1812,7 +1811,7 @@ __metadata: "@midnight-ntwrk/compact-runtime": "npm:^0.8.1" "@midnight-ntwrk/ledger": "npm:^4.0.0" "@midnight-ntwrk/zswap": "npm:^4.0.0" - "@types/node": "npm:^22" + "@types/node": "npm:22.14.0" fast-check: "npm:^3.15.0" ts-node: "npm:^10.9.2" turbo: "npm:^2.5.1" @@ -1909,9 +1908,9 @@ __metadata: linkType: hard "pathval@npm:^2.0.0": - version: 2.0.0 - resolution: "pathval@npm:2.0.0" - checksum: 10/b91575bf9cdf01757afd7b5e521eb8a0b874a49bc972d08e0047cfea0cd3c019f5614521d4bc83d2855e3fcc331db6817dfd533dd8f3d90b16bc76fad2450fc1 + version: 2.0.1 + resolution: "pathval@npm:2.0.1" + checksum: 10/f5e8b82f6b988a5bba197970af050268fd800780d0f9ee026e6f0b544ac4b17ab52bebeabccb790d63a794530a1641ae399ad07ecfc67ad337504c85dc9e5693 languageName: node linkType: hard From 7aecaf7eda7ad94c49ad73daa7819a558fa97738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 26 Jun 2025 02:24:27 -0400 Subject: [PATCH 254/282] fmt file --- contracts/utils/src/test/utils.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 9f618a37..1398d4d9 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -92,4 +92,4 @@ describe('Utils', () => { expect(contract.emptyString()).toBe(EMPTY_STRING); }); }); -}); \ No newline at end of file +}); From fe55c879516f6e4afd3b3f712c34f2eb28c62eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 26 Jun 2025 02:31:25 -0400 Subject: [PATCH 255/282] Fix build issues --- contracts/fungibleToken/src/test/utils/test.ts | 2 +- contracts/utils/src/test/utils/address.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/fungibleToken/src/test/utils/test.ts b/contracts/fungibleToken/src/test/utils/test.ts index d467e572..9fd2d4f6 100644 --- a/contracts/fungibleToken/src/test/utils/test.ts +++ b/contracts/fungibleToken/src/test/utils/test.ts @@ -6,7 +6,7 @@ import { QueryContext, emptyZswapLocalState, } from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types/test'; +import type { IContractSimulator } from '../types/test.js'; /** * Constructs a `CircuitContext` from the given state and sender information. diff --git a/contracts/utils/src/test/utils/address.ts b/contracts/utils/src/test/utils/address.ts index af4ed548..f288ae82 100644 --- a/contracts/utils/src/test/utils/address.ts +++ b/contracts/utils/src/test/utils/address.ts @@ -3,7 +3,7 @@ import { encodeCoinPublicKey, } from '@midnight-ntwrk/compact-runtime'; import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import type * as Compact from '../../artifacts/MockNonFungibleToken/contract/index.cjs'; +import type * as Compact from '../../artifacts/MockUtils/contract/index.cjs'; const PREFIX_ADDRESS = '0200'; From fd7b0ddd2aa58dba2edc28ca03556a5f7aedc22b Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 3 Apr 2025 23:59:27 -0500 Subject: [PATCH 256/282] add utils package --- contracts/utils/contract/.eslintignore | 1 + contracts/utils/contract/.eslintrc.cjs | 30 ++ contracts/utils/contract/jest.config.ts | 28 ++ contracts/utils/contract/js-resolver.cjs | 16 + contracts/utils/contract/package.json | 29 ++ .../utils/contract/src/MockUtils.compact | 13 + contracts/utils/contract/src/Utils.compact | 24 ++ .../utils/contract/src/test/UtilsSimulator.ts | 308 ++++++++++++++++++ contracts/utils/contract/src/test/types.ts | 4 + .../utils/contract/src/test/utils.test.ts | 23 ++ contracts/utils/contract/src/test/utils.ts | 78 +++++ contracts/utils/contract/src/types/index.ts | 1 + contracts/utils/contract/src/types/test.ts | 23 ++ contracts/utils/contract/src/utils/index.ts | 1 + contracts/utils/contract/src/utils/test.ts | 67 ++++ .../contract/src/witnesses/UtilsWitnesses.ts | 7 + .../utils/contract/src/witnesses/index.ts | 2 + contracts/utils/contract/tsconfig.build.json | 5 + contracts/utils/contract/tsconfig.json | 21 ++ 19 files changed, 681 insertions(+) create mode 100644 contracts/utils/contract/.eslintignore create mode 100644 contracts/utils/contract/.eslintrc.cjs create mode 100644 contracts/utils/contract/jest.config.ts create mode 100644 contracts/utils/contract/js-resolver.cjs create mode 100644 contracts/utils/contract/package.json create mode 100644 contracts/utils/contract/src/MockUtils.compact create mode 100644 contracts/utils/contract/src/Utils.compact create mode 100644 contracts/utils/contract/src/test/UtilsSimulator.ts create mode 100644 contracts/utils/contract/src/test/types.ts create mode 100644 contracts/utils/contract/src/test/utils.test.ts create mode 100644 contracts/utils/contract/src/test/utils.ts create mode 100644 contracts/utils/contract/src/types/index.ts create mode 100644 contracts/utils/contract/src/types/test.ts create mode 100644 contracts/utils/contract/src/utils/index.ts create mode 100644 contracts/utils/contract/src/utils/test.ts create mode 100644 contracts/utils/contract/src/witnesses/UtilsWitnesses.ts create mode 100644 contracts/utils/contract/src/witnesses/index.ts create mode 100644 contracts/utils/contract/tsconfig.build.json create mode 100644 contracts/utils/contract/tsconfig.json diff --git a/contracts/utils/contract/.eslintignore b/contracts/utils/contract/.eslintignore new file mode 100644 index 00000000..652df825 --- /dev/null +++ b/contracts/utils/contract/.eslintignore @@ -0,0 +1 @@ +src/managed diff --git a/contracts/utils/contract/.eslintrc.cjs b/contracts/utils/contract/.eslintrc.cjs new file mode 100644 index 00000000..581f1d49 --- /dev/null +++ b/contracts/utils/contract/.eslintrc.cjs @@ -0,0 +1,30 @@ +module.exports = { + env: { + browser: true, + es2021: true, + node: true, + jest: true, + }, + extends: [ + 'standard-with-typescript', + 'plugin:prettier/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + ], + overrides: [], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['tsconfig.json'], + }, + rules: { + '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 + '@typescript-eslint/no-floating-promises': 'warn', + '@typescript-eslint/promise-function-async': 'off', + '@typescript-eslint/no-redeclare': 'off', + '@typescript-eslint/no-invalid-void-type': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/consistent-type-definitions': 'off' + }, +}; diff --git a/contracts/utils/contract/jest.config.ts b/contracts/utils/contract/jest.config.ts new file mode 100644 index 00000000..edbdaeba --- /dev/null +++ b/contracts/utils/contract/jest.config.ts @@ -0,0 +1,28 @@ +import type { Config } from "@jest/types"; + +const config: Config.InitialOptions = { + preset: "ts-jest/presets/default-esm", + testEnvironment: "node", + verbose: true, + roots: [""], + modulePaths: [""], + passWithNoTests: false, + testMatch: ["**/*.test.ts"], + extensionsToTreatAsEsm: [".ts"], + collectCoverage: true, + resolver: '/js-resolver.cjs', + coverageThreshold: { + global: { + //branches: 60, + //functions: 75, + //lines: 70, + }, + }, + reporters: [ + "default", + ["jest-junit", { outputDirectory: "reports", outputName: "report.xml" }], + ["jest-html-reporters", { publicPath: "reports", filename: "report.html" }], + ], +}; + +export default config; diff --git a/contracts/utils/contract/js-resolver.cjs b/contracts/utils/contract/js-resolver.cjs new file mode 100644 index 00000000..cc9ed285 --- /dev/null +++ b/contracts/utils/contract/js-resolver.cjs @@ -0,0 +1,16 @@ +const jsResolver = (path, options) => { + const jsExtRegex = /\.js$/i + const resolver = options.defaultResolver + if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { + const newPath = path.replace(jsExtRegex, '.ts'); + try { + return resolver(newPath, options) + } catch { + // use default resolver + } + } + + return resolver(path, options) +} + +module.exports = jsResolver diff --git a/contracts/utils/contract/package.json b/contracts/utils/contract/package.json new file mode 100644 index 00000000..40c57157 --- /dev/null +++ b/contracts/utils/contract/package.json @@ -0,0 +1,29 @@ +{ + "name": "@openzeppelin-midnight-contracts/utils-contract", + "type": "module", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "scripts": { + "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", + "test": "NODE_OPTIONS=--experimental-vm-modules jest", + "prepack": "yarn build", + "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/Utils.compact ./dist", + "lint": "eslint src", + "typecheck": "tsc -p tsconfig.json --noEmit" + }, + "devDependencies": { + "@midnight-ntwrk/compact": "workspace:*", + "eslint": "^8.52.0", + "jest": "^29.7.0", + "typescript": "^5.2.2" + } +} diff --git a/contracts/utils/contract/src/MockUtils.compact b/contracts/utils/contract/src/MockUtils.compact new file mode 100644 index 00000000..e23c0f09 --- /dev/null +++ b/contracts/utils/contract/src/MockUtils.compact @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.14.0; + +import CompactStandardLibrary; + +import Utils prefix Utils_; + +export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; + +export pure circuit isZero(keyOrAddress: Either): Boolean { + return Utils_isZero(keyOrAddress); +} diff --git a/contracts/utils/contract/src/Utils.compact b/contracts/utils/contract/src/Utils.compact new file mode 100644 index 00000000..b0dbf3f5 --- /dev/null +++ b/contracts/utils/contract/src/Utils.compact @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.14.0; + +module Utils { + import CompactStandardLibrary; + + /** + * @description Returns whether `keyOrAddress` is the zero address. + * @todo Move to a utils contract since this will likely be reused. + * + * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @return {Boolean} - Returns true if `keyOrAddress` is zero. + */ + export pure circuit isZero(keyOrAddress: Either): Boolean { + const zero = pad(32, ""); + + if (keyOrAddress.is_left) { + return keyOrAddress == left(ZswapCoinPublicKey{ zero }); + } else { + return keyOrAddress == right(ContractAddress{ zero }); + } + } +} diff --git a/contracts/utils/contract/src/test/UtilsSimulator.ts b/contracts/utils/contract/src/test/UtilsSimulator.ts new file mode 100644 index 00000000..34995957 --- /dev/null +++ b/contracts/utils/contract/src/test/UtilsSimulator.ts @@ -0,0 +1,308 @@ +import { + type CircuitContext, + CoinPublicKey, + type ContractState, + QueryContext, + constructorContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import { sampleContractAddress } from '@midnight-ntwrk/zswap'; +import { + type Ledger, + Contract as MockUtils, + ledger, + Either, + ZswapCoinPublicKey, + ContractAddress, +} from '../artifacts/MockUtils/contract/index.cjs'; // Combined imports +import { MaybeString } from './types.js'; +import type { IContractSimulator } from '../types/index.js'; +import { UtilsPrivateState, UtilsWitnesses } from '../witnesses/index.js'; + +/** + * @description A simulator implementation of an utils contract for testing purposes. + * @template P - The private state type, fixed to UtilsPrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class UtilsContractSimulator + implements IContractSimulator +{ + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockUtils; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor() { + this.contract = new MockUtils( + UtilsWitnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)) + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type UtilsPrivateState. + */ + public getCurrentPrivateState(): UtilsPrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + +// /** +// * @description Returns the token name. +// * @returns The token name. +// */ +// public name(): MaybeString { +// return this.contract.impureCircuits.name(this.circuitContext).result; +// } +// +// /** +// * @description Returns the symbol of the token. +// * @returns The token name. +// */ +// public symbol(): MaybeString { +// return this.contract.impureCircuits.symbol(this.circuitContext).result; +// } +// +// /** +// * @description Returns the number of decimals used to get its user representation. +// * @returns The account's token balance. +// */ +// public decimals(): bigint { +// return this.contract.impureCircuits.decimals(this.circuitContext).result; +// } +// +// /** +// * @description Returns the value of tokens in existence. +// * @returns The total supply of tokens. +// */ +// public totalSupply(): bigint { +// return this.contract.impureCircuits.totalSupply(this.circuitContext).result; +// } +// +// /** +// * @description Returns the value of tokens owned by `account`. +// * @param account The public key or contract address to query. +// * @returns The account's token balance. +// */ +// public balanceOf(account: Either): bigint { +// return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; +// } +// +// /** +// * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` +// * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. +// * @param owner The public key or contract address of approver. +// * @param spender The public key or contract address of spender. +// * @returns The `spender`'s allowance over `owner`'s tokens. +// */ +// public allowance( +// owner: Either, +// spender: Either +// ): bigint { +// return this.contract.impureCircuits.allowance(this.circuitContext, owner, spender).result; +// } +// +// /** +// * @description Moves a `value` amount of tokens from the caller's account to `to`. +// * @param to The recipient of the transfer, either a user or a contract. +// * @param value The amount to transfer. +// * @param sender The simulated caller. +// * @returns As per the IUtils spec, this MUST return true. +// */ +// public transfer(to: Either, value: bigint, sender?: CoinPublicKey): boolean { +// const res = this.contract.impureCircuits.transfer({ +// ...this.circuitContext, +// currentZswapLocalState: sender +// ? emptyZswapLocalState(sender) +// : this.circuitContext.currentZswapLocalState, +// }, to, value +// ); +// +// this.circuitContext = res.context; +// return res.result; +// } +// +// /** +// * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. +// * `value` is the deducted from the caller's allowance. +// * @param from The current owner of the tokens for the transfer, either a user or a contract. +// * @param to The recipient of the transfer, either a user or a contract. +// * @param value The amount to transfer. +// * @param sender The simulated caller. +// * @returns As per the IUtils spec, this MUST return true. +// */ +// public transferFrom( +// from: Either, +// to: Either, +// value: bigint, +// sender?: CoinPublicKey +// ): boolean { +// const res = this.contract.impureCircuits.transferFrom({ +// ...this.circuitContext, +// currentZswapLocalState: sender +// ? emptyZswapLocalState(sender) +// : this.circuitContext.currentZswapLocalState, +// }, +// from, to, value +// ); +// +// this.circuitContext = res.context; +// return res.result; +// } +// +// /** +// * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. +// * @param spender The Zswap key or ContractAddress that may spend on behalf of the caller. +// * @param value The amount of tokens the `spender` may spend. +// * @param sender The simulated caller. +// * @returns Returns a boolean value indicating whether the operation succeeded. +// */ +// public approve(spender: Either, value: bigint, sender?: CoinPublicKey): boolean { +// const res = this.contract.impureCircuits.approve({ +// ...this.circuitContext, +// currentZswapLocalState: sender +// ? emptyZswapLocalState(sender) +// : this.circuitContext.currentZswapLocalState, +// }, +// spender, value +// ); +// +// this.circuitContext = res.context; +// return res.result; +// } +// +// /// +// /// Internal +// /// +// +// /** +// * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. +// * This internal function is equivalent to `approve`, and can be used to +// * e.g. set automatic allowances for certain subsystems, etc. +// * @param owner The owner of the tokens. +// * @param spender The spender of the tokens. +// * @param value The amount of tokens `spender` may spend on behalf of `owner`. +// * @returns None. +// */ +// public _approve( +// owner: Either, +// spender: Either, +// value: bigint +// ) { +// this.circuitContext = this.contract.impureCircuits._approve(this.circuitContext, owner, spender, value).context; +// } +// +// /** +// * @description Moves a `value` amount of tokens from `from` to `to`. +// * This internal function is equivalent to {transfer}, and can be used to +// * e.g. implement automatic token fees, slashing mechanisms, etc. +// * @param from The owner of the tokens to transfer. +// * @param to The receipient of the transferred tokens. +// * @param value The amount of tokens to transfer. +// */ +// public _transfer( +// from: Either, +// to: Either, +// value: bigint, +// ) { +// this.circuitContext = this.contract.impureCircuits._transfer(this.circuitContext, from, to, value).context; +// } +// +// /** +// * @description Creates a `value` amount of tokens and assigns them to `account`, +// * by transferring it from the zero address. Relies on the `update` mechanism. +// * @param account The recipient of tokens minted. +// * @param value The amount of tokens minted. +// */ +// public _mint(account: Either, value: bigint) { +// this.circuitContext = this.contract.impureCircuits._mint(this.circuitContext, account, value).context; +// } +// +// /** +// * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. +// * Relies on the `_update` mechanism. +// * @param account The target owner of tokens to burn. +// * @param value The amount of tokens to burn. +// */ +// public _burn(account: Either, value: bigint) { +// this.circuitContext = this.contract.impureCircuits._burn(this.circuitContext, account, value).context; +// } +// +// /** +// * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` +// * (or `to`) is the zero address. +// * @param from The original owner of the tokens moved (which is 0 if tokens are minted). +// * @param to The recipient of the tokens moved (which is 0 if tokens are burned). +// * @param value The amount of tokens moved from `from` to `to`. +// */ +// public _update( +// from: Either, +// to: Either, +// value: bigint +// ) { +// this.circuitContext = this.contract.impureCircuits._update(this.circuitContext, from, to, value).context; +// } +// +// /** +// * @description Updates `owner`'s allowance for `spender` based on spent `value`. +// * Does not update the allowance value in case of infinite allowance. +// * @param owner The owner of the tokens. +// * @param spender The spender of the tokens. +// * @param value The amount of token allowance to spend. +// */ +// public _spendAllowance( +// owner: Either, +// spender: Either, +// value: bigint +// ) { +// this.circuitContext = this.contract.impureCircuits._spendAllowance(this.circuitContext, owner, spender, value).context; +// } +// + /** + * @description Returns whether `keyOrAddress` is the zero address. + * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @returns Returns true if `keyOrAddress` is zero. + */ + public isZero(keyOrAddress: Either): boolean { + return this.contract.circuits.isZero(this.circuitContext, keyOrAddress).result; + } +} diff --git a/contracts/utils/contract/src/test/types.ts b/contracts/utils/contract/src/test/types.ts new file mode 100644 index 00000000..4735fab2 --- /dev/null +++ b/contracts/utils/contract/src/test/types.ts @@ -0,0 +1,4 @@ +export type MaybeString = { + is_some: boolean, + value: string +} diff --git a/contracts/utils/contract/src/test/utils.test.ts b/contracts/utils/contract/src/test/utils.test.ts new file mode 100644 index 00000000..499ad79e --- /dev/null +++ b/contracts/utils/contract/src/test/utils.test.ts @@ -0,0 +1,23 @@ +import { UtilsContractSimulator } from './UtilsSimulator'; +import * as utils from './utils.js'; + +const Z_OWNER = utils.createEitherTestUser('OWNER'); +const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); + +let contract: UtilsContractSimulator; + +describe('Utils', () => { + contract = new UtilsContractSimulator(); + + describe('isZero', () => { + it('should return zero for the zero address', () => { + expect(contract.isZero(utils.ZERO_KEY)).toBeTruthy; + expect(contract.isZero(utils.ZERO_ADDRESS)).toBeTruthy; + }); + + it('should not return zero for nonzero addresses', () => { + expect(contract.isZero(Z_OWNER)).toBeFalsy; + expect(contract.isZero(SOME_CONTRACT)).toBeFalsy; + }); + }); +}); diff --git a/contracts/utils/contract/src/test/utils.ts b/contracts/utils/contract/src/test/utils.ts new file mode 100644 index 00000000..e360bda1 --- /dev/null +++ b/contracts/utils/contract/src/test/utils.ts @@ -0,0 +1,78 @@ +import { encodeContractAddress } from '@midnight-ntwrk/ledger'; +import * as Compact from '../artifacts/MockUtils/contract/index.cjs'; +import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; + +const PREFIX_ADDRESS = "0200"; + +export const pad = (s: string, n: number): Uint8Array => { + const encoder = new TextEncoder(); + const utf8Bytes = encoder.encode(s); + if (n < utf8Bytes.length) { + throw new Error(`The padded length n must be at least ${utf8Bytes.length}`); + } + const paddedArray = new Uint8Array(n); + paddedArray.set(utf8Bytes); + return paddedArray; +} + +/** + * @description Generates ZswapCoinPublicKey from `str` for testing purposes. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { + const toHex = Buffer.from(str, 'ascii').toString('hex'); + return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; +} + +/** + * @description Generates ContractAddress from `str` for testing purposes. + * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToAddress = (str: string): Compact.ContractAddress => { + const toHex = Buffer.from(str, 'ascii').toString('hex'); + const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); + return { bytes: encodeContractAddress(fullAddress) }; +} + +/** + * @description Generates an Either object for ZswapCoinPublicKey for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ZswapCoinPublicKey. + */ +export const createEitherTestUser = (str: string) => { + return { + is_left: true, + left: encodeToPK(str), + right: encodeToAddress('') + } +} + +/** + * @description Generates an Either object for ContractAddress for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ContractAddress. + */ +export const createEitherTestContractAddress = (str: string) => { + return { + is_left: false, + left: encodeToPK(''), + right: encodeToAddress(str) + } +} + +export const ZERO_KEY = { + is_left: true, + left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, + right: encodeToAddress('') +} + +export const ZERO_ADDRESS = { + is_left: false, + left: encodeToPK(''), + right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) } +} diff --git a/contracts/utils/contract/src/types/index.ts b/contracts/utils/contract/src/types/index.ts new file mode 100644 index 00000000..db642b5e --- /dev/null +++ b/contracts/utils/contract/src/types/index.ts @@ -0,0 +1 @@ +export type { IContractSimulator } from './test'; diff --git a/contracts/utils/contract/src/types/test.ts b/contracts/utils/contract/src/types/test.ts new file mode 100644 index 00000000..10fb6c98 --- /dev/null +++ b/contracts/utils/contract/src/types/test.ts @@ -0,0 +1,23 @@ +import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; + +/** + * Generic interface for mock contract implementations. + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + */ +export interface IContractSimulator { + /** The contract's deployed address. */ + readonly contractAddress: string; + + /** The current circuit context. */ + circuitContext: CircuitContext

; + + /** Retrieves the current ledger state. */ + getCurrentPublicState(): L; + + /** Retrieves the current private state. */ + getCurrentPrivateState(): P; + + /** Retrieves the current contract state. */ + getCurrentContractState(): ContractState; +} diff --git a/contracts/utils/contract/src/utils/index.ts b/contracts/utils/contract/src/utils/index.ts new file mode 100644 index 00000000..14e02ef2 --- /dev/null +++ b/contracts/utils/contract/src/utils/index.ts @@ -0,0 +1 @@ +export { useCircuitContext as circuitContext } from './test'; diff --git a/contracts/utils/contract/src/utils/test.ts b/contracts/utils/contract/src/utils/test.ts new file mode 100644 index 00000000..940ed612 --- /dev/null +++ b/contracts/utils/contract/src/utils/test.ts @@ -0,0 +1,67 @@ +import { + type CircuitContext, + type CoinPublicKey, + type ContractAddress, + type ContractState, + QueryContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import type { IContractSimulator } from '../types'; + +/** + * Constructs a `CircuitContext` from the given state and sender information. + * + * This is typically used at runtime to provide the necessary context + * for executing circuits, including contract state, private state, + * sender identity, and transaction data. + * + * @template P - The type of the contract's private state. + * @param privateState - The current private state of the contract. + * @param contractState - The full contract state, including public and private data. + * @param sender - The public key of the sender (used in the circuit). + * @param contractAddress - The address of the deployed contract. + * @returns A fully populated `CircuitContext` for circuit execution. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContext

( + privateState: P, + contractState: ContractState, + sender: CoinPublicKey, + contractAddress: ContractAddress, +): CircuitContext

{ + return { + originalState: contractState, + currentPrivateState: privateState, + transactionContext: new QueryContext(contractState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} + +/** + * Prepares a new `CircuitContext` using the given sender and contract. + * + * Useful for mocking or updating the circuit context with a custom sender. + * + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + * @template C - The specific type of the contract implementing `MockContract`. + * @param contract - The contract instance implementing `MockContract`. + * @param sender - The public key to set as the sender in the new circuit context. + * @returns A new `CircuitContext` with the sender and updated context values. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContextSender>( + contract: C, + sender: CoinPublicKey, +): CircuitContext

{ + const currentPrivateState = contract.getCurrentPrivateState(); + const originalState = contract.getCurrentContractState(); + const contractAddress = contract.contractAddress; + + return { + originalState, + currentPrivateState, + transactionContext: new QueryContext(originalState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} diff --git a/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts b/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts new file mode 100644 index 00000000..3b7d3340 --- /dev/null +++ b/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts @@ -0,0 +1,7 @@ +// This is how we type an empty object. +export type UtilsPrivateState = Record; + +export const witnesses = {}; +export const UtilsWitnesses = {}; + +export const createUtilsPrivateState = () => ({}); diff --git a/contracts/utils/contract/src/witnesses/index.ts b/contracts/utils/contract/src/witnesses/index.ts new file mode 100644 index 00000000..1c74ba34 --- /dev/null +++ b/contracts/utils/contract/src/witnesses/index.ts @@ -0,0 +1,2 @@ +export * from '../artifacts/utils/contract/index.cjs'; +export * from './UtilsWitnesses.js'; diff --git a/contracts/utils/contract/tsconfig.build.json b/contracts/utils/contract/tsconfig.build.json new file mode 100644 index 00000000..f1132509 --- /dev/null +++ b/contracts/utils/contract/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["src/test/**/*.ts"], + "compilerOptions": {} +} diff --git a/contracts/utils/contract/tsconfig.json b/contracts/utils/contract/tsconfig.json new file mode 100644 index 00000000..3e90b0a9 --- /dev/null +++ b/contracts/utils/contract/tsconfig.json @@ -0,0 +1,21 @@ +{ + "include": ["src/**/*.ts"], + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "lib": ["ESNext"], + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "node", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": true, + "strict": true, + "isolatedModules": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true + } +} From 0c437af12d65adf03dc9f4c167b7831c772ca031 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 00:12:22 -0500 Subject: [PATCH 257/282] add utils contract --- contracts/utils/contract/.eslintignore | 1 - contracts/utils/contract/.eslintrc.cjs | 30 -- contracts/utils/contract/jest.config.ts | 28 -- contracts/utils/contract/js-resolver.cjs | 16 - contracts/utils/contract/package.json | 29 -- contracts/utils/contract/src/Utils.compact | 24 -- .../utils/contract/src/test/UtilsSimulator.ts | 308 ------------------ contracts/utils/contract/src/test/types.ts | 4 - .../utils/contract/src/test/utils.test.ts | 23 -- contracts/utils/contract/src/test/utils.ts | 78 ----- contracts/utils/contract/src/types/index.ts | 1 - contracts/utils/contract/src/types/test.ts | 23 -- contracts/utils/contract/src/utils/index.ts | 1 - contracts/utils/contract/src/utils/test.ts | 67 ---- .../contract/src/witnesses/UtilsWitnesses.ts | 7 - contracts/utils/contract/tsconfig.build.json | 5 - contracts/utils/contract/tsconfig.json | 21 -- .../{contract => }/src/MockUtils.compact | 2 +- contracts/utils/src/test/UtilsSimulator.ts | 94 ++++++ contracts/utils/src/test/utils/address.ts | 3 +- contracts/utils/src/test/utils/index.ts | 4 + .../{contract => }/src/witnesses/index.ts | 0 22 files changed, 101 insertions(+), 668 deletions(-) delete mode 100644 contracts/utils/contract/.eslintignore delete mode 100644 contracts/utils/contract/.eslintrc.cjs delete mode 100644 contracts/utils/contract/jest.config.ts delete mode 100644 contracts/utils/contract/js-resolver.cjs delete mode 100644 contracts/utils/contract/package.json delete mode 100644 contracts/utils/contract/src/Utils.compact delete mode 100644 contracts/utils/contract/src/test/UtilsSimulator.ts delete mode 100644 contracts/utils/contract/src/test/types.ts delete mode 100644 contracts/utils/contract/src/test/utils.test.ts delete mode 100644 contracts/utils/contract/src/test/utils.ts delete mode 100644 contracts/utils/contract/src/types/index.ts delete mode 100644 contracts/utils/contract/src/types/test.ts delete mode 100644 contracts/utils/contract/src/utils/index.ts delete mode 100644 contracts/utils/contract/src/utils/test.ts delete mode 100644 contracts/utils/contract/src/witnesses/UtilsWitnesses.ts delete mode 100644 contracts/utils/contract/tsconfig.build.json delete mode 100644 contracts/utils/contract/tsconfig.json rename contracts/utils/{contract => }/src/MockUtils.compact (81%) create mode 100644 contracts/utils/src/test/UtilsSimulator.ts create mode 100644 contracts/utils/src/test/utils/index.ts rename contracts/utils/{contract => }/src/witnesses/index.ts (100%) diff --git a/contracts/utils/contract/.eslintignore b/contracts/utils/contract/.eslintignore deleted file mode 100644 index 652df825..00000000 --- a/contracts/utils/contract/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -src/managed diff --git a/contracts/utils/contract/.eslintrc.cjs b/contracts/utils/contract/.eslintrc.cjs deleted file mode 100644 index 581f1d49..00000000 --- a/contracts/utils/contract/.eslintrc.cjs +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - node: true, - jest: true, - }, - extends: [ - 'standard-with-typescript', - 'plugin:prettier/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - overrides: [], - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['tsconfig.json'], - }, - rules: { - '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 - '@typescript-eslint/no-floating-promises': 'warn', - '@typescript-eslint/promise-function-async': 'off', - '@typescript-eslint/no-redeclare': 'off', - '@typescript-eslint/no-invalid-void-type': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/consistent-type-definitions': 'off' - }, -}; diff --git a/contracts/utils/contract/jest.config.ts b/contracts/utils/contract/jest.config.ts deleted file mode 100644 index edbdaeba..00000000 --- a/contracts/utils/contract/jest.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Config } from "@jest/types"; - -const config: Config.InitialOptions = { - preset: "ts-jest/presets/default-esm", - testEnvironment: "node", - verbose: true, - roots: [""], - modulePaths: [""], - passWithNoTests: false, - testMatch: ["**/*.test.ts"], - extensionsToTreatAsEsm: [".ts"], - collectCoverage: true, - resolver: '/js-resolver.cjs', - coverageThreshold: { - global: { - //branches: 60, - //functions: 75, - //lines: 70, - }, - }, - reporters: [ - "default", - ["jest-junit", { outputDirectory: "reports", outputName: "report.xml" }], - ["jest-html-reporters", { publicPath: "reports", filename: "report.html" }], - ], -}; - -export default config; diff --git a/contracts/utils/contract/js-resolver.cjs b/contracts/utils/contract/js-resolver.cjs deleted file mode 100644 index cc9ed285..00000000 --- a/contracts/utils/contract/js-resolver.cjs +++ /dev/null @@ -1,16 +0,0 @@ -const jsResolver = (path, options) => { - const jsExtRegex = /\.js$/i - const resolver = options.defaultResolver - if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { - const newPath = path.replace(jsExtRegex, '.ts'); - try { - return resolver(newPath, options) - } catch { - // use default resolver - } - } - - return resolver(path, options) -} - -module.exports = jsResolver diff --git a/contracts/utils/contract/package.json b/contracts/utils/contract/package.json deleted file mode 100644 index 40c57157..00000000 --- a/contracts/utils/contract/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "@openzeppelin-midnight-contracts/utils-contract", - "type": "module", - "main": "dist/index.js", - "module": "dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "require": "./dist/index.js", - "import": "./dist/index.js", - "default": "./dist/index.js" - } - }, - "scripts": { - "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", - "test": "NODE_OPTIONS=--experimental-vm-modules jest", - "prepack": "yarn build", - "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/Utils.compact ./dist", - "lint": "eslint src", - "typecheck": "tsc -p tsconfig.json --noEmit" - }, - "devDependencies": { - "@midnight-ntwrk/compact": "workspace:*", - "eslint": "^8.52.0", - "jest": "^29.7.0", - "typescript": "^5.2.2" - } -} diff --git a/contracts/utils/contract/src/Utils.compact b/contracts/utils/contract/src/Utils.compact deleted file mode 100644 index b0dbf3f5..00000000 --- a/contracts/utils/contract/src/Utils.compact +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.14.0; - -module Utils { - import CompactStandardLibrary; - - /** - * @description Returns whether `keyOrAddress` is the zero address. - * @todo Move to a utils contract since this will likely be reused. - * - * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. - * @return {Boolean} - Returns true if `keyOrAddress` is zero. - */ - export pure circuit isZero(keyOrAddress: Either): Boolean { - const zero = pad(32, ""); - - if (keyOrAddress.is_left) { - return keyOrAddress == left(ZswapCoinPublicKey{ zero }); - } else { - return keyOrAddress == right(ContractAddress{ zero }); - } - } -} diff --git a/contracts/utils/contract/src/test/UtilsSimulator.ts b/contracts/utils/contract/src/test/UtilsSimulator.ts deleted file mode 100644 index 34995957..00000000 --- a/contracts/utils/contract/src/test/UtilsSimulator.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { - type CircuitContext, - CoinPublicKey, - type ContractState, - QueryContext, - constructorContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; -import { - type Ledger, - Contract as MockUtils, - ledger, - Either, - ZswapCoinPublicKey, - ContractAddress, -} from '../artifacts/MockUtils/contract/index.cjs'; // Combined imports -import { MaybeString } from './types.js'; -import type { IContractSimulator } from '../types/index.js'; -import { UtilsPrivateState, UtilsWitnesses } from '../witnesses/index.js'; - -/** - * @description A simulator implementation of an utils contract for testing purposes. - * @template P - The private state type, fixed to UtilsPrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. - */ -export class UtilsContractSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockUtils; - - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor() { - this.contract = new MockUtils( - UtilsWitnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)) - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type UtilsPrivateState. - */ - public getCurrentPrivateState(): UtilsPrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; - } - -// /** -// * @description Returns the token name. -// * @returns The token name. -// */ -// public name(): MaybeString { -// return this.contract.impureCircuits.name(this.circuitContext).result; -// } -// -// /** -// * @description Returns the symbol of the token. -// * @returns The token name. -// */ -// public symbol(): MaybeString { -// return this.contract.impureCircuits.symbol(this.circuitContext).result; -// } -// -// /** -// * @description Returns the number of decimals used to get its user representation. -// * @returns The account's token balance. -// */ -// public decimals(): bigint { -// return this.contract.impureCircuits.decimals(this.circuitContext).result; -// } -// -// /** -// * @description Returns the value of tokens in existence. -// * @returns The total supply of tokens. -// */ -// public totalSupply(): bigint { -// return this.contract.impureCircuits.totalSupply(this.circuitContext).result; -// } -// -// /** -// * @description Returns the value of tokens owned by `account`. -// * @param account The public key or contract address to query. -// * @returns The account's token balance. -// */ -// public balanceOf(account: Either): bigint { -// return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; -// } -// -// /** -// * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` -// * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. -// * @param owner The public key or contract address of approver. -// * @param spender The public key or contract address of spender. -// * @returns The `spender`'s allowance over `owner`'s tokens. -// */ -// public allowance( -// owner: Either, -// spender: Either -// ): bigint { -// return this.contract.impureCircuits.allowance(this.circuitContext, owner, spender).result; -// } -// -// /** -// * @description Moves a `value` amount of tokens from the caller's account to `to`. -// * @param to The recipient of the transfer, either a user or a contract. -// * @param value The amount to transfer. -// * @param sender The simulated caller. -// * @returns As per the IUtils spec, this MUST return true. -// */ -// public transfer(to: Either, value: bigint, sender?: CoinPublicKey): boolean { -// const res = this.contract.impureCircuits.transfer({ -// ...this.circuitContext, -// currentZswapLocalState: sender -// ? emptyZswapLocalState(sender) -// : this.circuitContext.currentZswapLocalState, -// }, to, value -// ); -// -// this.circuitContext = res.context; -// return res.result; -// } -// -// /** -// * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. -// * `value` is the deducted from the caller's allowance. -// * @param from The current owner of the tokens for the transfer, either a user or a contract. -// * @param to The recipient of the transfer, either a user or a contract. -// * @param value The amount to transfer. -// * @param sender The simulated caller. -// * @returns As per the IUtils spec, this MUST return true. -// */ -// public transferFrom( -// from: Either, -// to: Either, -// value: bigint, -// sender?: CoinPublicKey -// ): boolean { -// const res = this.contract.impureCircuits.transferFrom({ -// ...this.circuitContext, -// currentZswapLocalState: sender -// ? emptyZswapLocalState(sender) -// : this.circuitContext.currentZswapLocalState, -// }, -// from, to, value -// ); -// -// this.circuitContext = res.context; -// return res.result; -// } -// -// /** -// * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. -// * @param spender The Zswap key or ContractAddress that may spend on behalf of the caller. -// * @param value The amount of tokens the `spender` may spend. -// * @param sender The simulated caller. -// * @returns Returns a boolean value indicating whether the operation succeeded. -// */ -// public approve(spender: Either, value: bigint, sender?: CoinPublicKey): boolean { -// const res = this.contract.impureCircuits.approve({ -// ...this.circuitContext, -// currentZswapLocalState: sender -// ? emptyZswapLocalState(sender) -// : this.circuitContext.currentZswapLocalState, -// }, -// spender, value -// ); -// -// this.circuitContext = res.context; -// return res.result; -// } -// -// /// -// /// Internal -// /// -// -// /** -// * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. -// * This internal function is equivalent to `approve`, and can be used to -// * e.g. set automatic allowances for certain subsystems, etc. -// * @param owner The owner of the tokens. -// * @param spender The spender of the tokens. -// * @param value The amount of tokens `spender` may spend on behalf of `owner`. -// * @returns None. -// */ -// public _approve( -// owner: Either, -// spender: Either, -// value: bigint -// ) { -// this.circuitContext = this.contract.impureCircuits._approve(this.circuitContext, owner, spender, value).context; -// } -// -// /** -// * @description Moves a `value` amount of tokens from `from` to `to`. -// * This internal function is equivalent to {transfer}, and can be used to -// * e.g. implement automatic token fees, slashing mechanisms, etc. -// * @param from The owner of the tokens to transfer. -// * @param to The receipient of the transferred tokens. -// * @param value The amount of tokens to transfer. -// */ -// public _transfer( -// from: Either, -// to: Either, -// value: bigint, -// ) { -// this.circuitContext = this.contract.impureCircuits._transfer(this.circuitContext, from, to, value).context; -// } -// -// /** -// * @description Creates a `value` amount of tokens and assigns them to `account`, -// * by transferring it from the zero address. Relies on the `update` mechanism. -// * @param account The recipient of tokens minted. -// * @param value The amount of tokens minted. -// */ -// public _mint(account: Either, value: bigint) { -// this.circuitContext = this.contract.impureCircuits._mint(this.circuitContext, account, value).context; -// } -// -// /** -// * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. -// * Relies on the `_update` mechanism. -// * @param account The target owner of tokens to burn. -// * @param value The amount of tokens to burn. -// */ -// public _burn(account: Either, value: bigint) { -// this.circuitContext = this.contract.impureCircuits._burn(this.circuitContext, account, value).context; -// } -// -// /** -// * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` -// * (or `to`) is the zero address. -// * @param from The original owner of the tokens moved (which is 0 if tokens are minted). -// * @param to The recipient of the tokens moved (which is 0 if tokens are burned). -// * @param value The amount of tokens moved from `from` to `to`. -// */ -// public _update( -// from: Either, -// to: Either, -// value: bigint -// ) { -// this.circuitContext = this.contract.impureCircuits._update(this.circuitContext, from, to, value).context; -// } -// -// /** -// * @description Updates `owner`'s allowance for `spender` based on spent `value`. -// * Does not update the allowance value in case of infinite allowance. -// * @param owner The owner of the tokens. -// * @param spender The spender of the tokens. -// * @param value The amount of token allowance to spend. -// */ -// public _spendAllowance( -// owner: Either, -// spender: Either, -// value: bigint -// ) { -// this.circuitContext = this.contract.impureCircuits._spendAllowance(this.circuitContext, owner, spender, value).context; -// } -// - /** - * @description Returns whether `keyOrAddress` is the zero address. - * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. - * @returns Returns true if `keyOrAddress` is zero. - */ - public isZero(keyOrAddress: Either): boolean { - return this.contract.circuits.isZero(this.circuitContext, keyOrAddress).result; - } -} diff --git a/contracts/utils/contract/src/test/types.ts b/contracts/utils/contract/src/test/types.ts deleted file mode 100644 index 4735fab2..00000000 --- a/contracts/utils/contract/src/test/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type MaybeString = { - is_some: boolean, - value: string -} diff --git a/contracts/utils/contract/src/test/utils.test.ts b/contracts/utils/contract/src/test/utils.test.ts deleted file mode 100644 index 499ad79e..00000000 --- a/contracts/utils/contract/src/test/utils.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { UtilsContractSimulator } from './UtilsSimulator'; -import * as utils from './utils.js'; - -const Z_OWNER = utils.createEitherTestUser('OWNER'); -const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); - -let contract: UtilsContractSimulator; - -describe('Utils', () => { - contract = new UtilsContractSimulator(); - - describe('isZero', () => { - it('should return zero for the zero address', () => { - expect(contract.isZero(utils.ZERO_KEY)).toBeTruthy; - expect(contract.isZero(utils.ZERO_ADDRESS)).toBeTruthy; - }); - - it('should not return zero for nonzero addresses', () => { - expect(contract.isZero(Z_OWNER)).toBeFalsy; - expect(contract.isZero(SOME_CONTRACT)).toBeFalsy; - }); - }); -}); diff --git a/contracts/utils/contract/src/test/utils.ts b/contracts/utils/contract/src/test/utils.ts deleted file mode 100644 index e360bda1..00000000 --- a/contracts/utils/contract/src/test/utils.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import * as Compact from '../artifacts/MockUtils/contract/index.cjs'; -import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; - -const PREFIX_ADDRESS = "0200"; - -export const pad = (s: string, n: number): Uint8Array => { - const encoder = new TextEncoder(); - const utf8Bytes = encoder.encode(s); - if (n < utf8Bytes.length) { - throw new Error(`The padded length n must be at least ${utf8Bytes.length}`); - } - const paddedArray = new Uint8Array(n); - paddedArray.set(utf8Bytes); - return paddedArray; -} - -/** - * @description Generates ZswapCoinPublicKey from `str` for testing purposes. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; -} - -/** - * @description Generates ContractAddress from `str` for testing purposes. - * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToAddress = (str: string): Compact.ContractAddress => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); - return { bytes: encodeContractAddress(fullAddress) }; -} - -/** - * @description Generates an Either object for ZswapCoinPublicKey for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ZswapCoinPublicKey. - */ -export const createEitherTestUser = (str: string) => { - return { - is_left: true, - left: encodeToPK(str), - right: encodeToAddress('') - } -} - -/** - * @description Generates an Either object for ContractAddress for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ContractAddress. - */ -export const createEitherTestContractAddress = (str: string) => { - return { - is_left: false, - left: encodeToPK(''), - right: encodeToAddress(str) - } -} - -export const ZERO_KEY = { - is_left: true, - left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, - right: encodeToAddress('') -} - -export const ZERO_ADDRESS = { - is_left: false, - left: encodeToPK(''), - right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) } -} diff --git a/contracts/utils/contract/src/types/index.ts b/contracts/utils/contract/src/types/index.ts deleted file mode 100644 index db642b5e..00000000 --- a/contracts/utils/contract/src/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { IContractSimulator } from './test'; diff --git a/contracts/utils/contract/src/types/test.ts b/contracts/utils/contract/src/types/test.ts deleted file mode 100644 index 10fb6c98..00000000 --- a/contracts/utils/contract/src/types/test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; - -/** - * Generic interface for mock contract implementations. - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - */ -export interface IContractSimulator { - /** The contract's deployed address. */ - readonly contractAddress: string; - - /** The current circuit context. */ - circuitContext: CircuitContext

; - - /** Retrieves the current ledger state. */ - getCurrentPublicState(): L; - - /** Retrieves the current private state. */ - getCurrentPrivateState(): P; - - /** Retrieves the current contract state. */ - getCurrentContractState(): ContractState; -} diff --git a/contracts/utils/contract/src/utils/index.ts b/contracts/utils/contract/src/utils/index.ts deleted file mode 100644 index 14e02ef2..00000000 --- a/contracts/utils/contract/src/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { useCircuitContext as circuitContext } from './test'; diff --git a/contracts/utils/contract/src/utils/test.ts b/contracts/utils/contract/src/utils/test.ts deleted file mode 100644 index 940ed612..00000000 --- a/contracts/utils/contract/src/utils/test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - QueryContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types'; - -/** - * Constructs a `CircuitContext` from the given state and sender information. - * - * This is typically used at runtime to provide the necessary context - * for executing circuits, including contract state, private state, - * sender identity, and transaction data. - * - * @template P - The type of the contract's private state. - * @param privateState - The current private state of the contract. - * @param contractState - The full contract state, including public and private data. - * @param sender - The public key of the sender (used in the circuit). - * @param contractAddress - The address of the deployed contract. - * @returns A fully populated `CircuitContext` for circuit execution. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContext

( - privateState: P, - contractState: ContractState, - sender: CoinPublicKey, - contractAddress: ContractAddress, -): CircuitContext

{ - return { - originalState: contractState, - currentPrivateState: privateState, - transactionContext: new QueryContext(contractState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} - -/** - * Prepares a new `CircuitContext` using the given sender and contract. - * - * Useful for mocking or updating the circuit context with a custom sender. - * - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - * @template C - The specific type of the contract implementing `MockContract`. - * @param contract - The contract instance implementing `MockContract`. - * @param sender - The public key to set as the sender in the new circuit context. - * @returns A new `CircuitContext` with the sender and updated context values. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContextSender>( - contract: C, - sender: CoinPublicKey, -): CircuitContext

{ - const currentPrivateState = contract.getCurrentPrivateState(); - const originalState = contract.getCurrentContractState(); - const contractAddress = contract.contractAddress; - - return { - originalState, - currentPrivateState, - transactionContext: new QueryContext(originalState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} diff --git a/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts b/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts deleted file mode 100644 index 3b7d3340..00000000 --- a/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts +++ /dev/null @@ -1,7 +0,0 @@ -// This is how we type an empty object. -export type UtilsPrivateState = Record; - -export const witnesses = {}; -export const UtilsWitnesses = {}; - -export const createUtilsPrivateState = () => ({}); diff --git a/contracts/utils/contract/tsconfig.build.json b/contracts/utils/contract/tsconfig.build.json deleted file mode 100644 index f1132509..00000000 --- a/contracts/utils/contract/tsconfig.build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["src/test/**/*.ts"], - "compilerOptions": {} -} diff --git a/contracts/utils/contract/tsconfig.json b/contracts/utils/contract/tsconfig.json deleted file mode 100644 index 3e90b0a9..00000000 --- a/contracts/utils/contract/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "include": ["src/**/*.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - "declaration": true, - "lib": ["ESNext"], - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "node", - "allowJs": true, - "forceConsistentCasingInFileNames": true, - "noImplicitAny": true, - "strict": true, - "isolatedModules": true, - "sourceMap": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "skipLibCheck": true - } -} diff --git a/contracts/utils/contract/src/MockUtils.compact b/contracts/utils/src/MockUtils.compact similarity index 81% rename from contracts/utils/contract/src/MockUtils.compact rename to contracts/utils/src/MockUtils.compact index e23c0f09..479a1fa2 100644 --- a/contracts/utils/contract/src/MockUtils.compact +++ b/contracts/utils/src/MockUtils.compact @@ -6,7 +6,7 @@ import CompactStandardLibrary; import Utils prefix Utils_; -export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; +export { ZswapCoinPublicKey, ContractAddress, Either }; export pure circuit isZero(keyOrAddress: Either): Boolean { return Utils_isZero(keyOrAddress); diff --git a/contracts/utils/src/test/UtilsSimulator.ts b/contracts/utils/src/test/UtilsSimulator.ts new file mode 100644 index 00000000..98190e5c --- /dev/null +++ b/contracts/utils/src/test/UtilsSimulator.ts @@ -0,0 +1,94 @@ +import { + type CircuitContext, + type ContractState, + QueryContext, + constructorContext, +} from '@midnight-ntwrk/compact-runtime'; +import { sampleContractAddress } from '@midnight-ntwrk/zswap'; +import { + type Ledger, + Contract as MockUtils, + ledger, + Either, + ZswapCoinPublicKey, + ContractAddress, +} from '../artifacts/MockUtils/contract/index.cjs'; // Combined imports +import type { IContractSimulator } from './types'; +import { UtilsPrivateState, UtilsWitnesses } from '../witnesses'; + +/** + * @description A simulator implementation of an utils contract for testing purposes. + * @template P - The private state type, fixed to UtilsPrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class UtilsContractSimulator + implements IContractSimulator +{ + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockUtils; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor() { + this.contract = new MockUtils( + UtilsWitnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)) + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type UtilsPrivateState. + */ + public getCurrentPrivateState(): UtilsPrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + + /** + * @description Returns whether `keyOrAddress` is the zero address. + * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @returns Returns true if `keyOrAddress` is zero. + */ + public isZero(keyOrAddress: Either): boolean { + return this.contract.circuits.isZero(this.circuitContext, keyOrAddress).result; + } +} diff --git a/contracts/utils/src/test/utils/address.ts b/contracts/utils/src/test/utils/address.ts index f288ae82..26466ab5 100644 --- a/contracts/utils/src/test/utils/address.ts +++ b/contracts/utils/src/test/utils/address.ts @@ -3,7 +3,8 @@ import { encodeCoinPublicKey, } from '@midnight-ntwrk/compact-runtime'; import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import type * as Compact from '../../artifacts/MockUtils/contract/index.cjs'; +import * as Compact from '../../artifacts/MockUtils/contract/index.cjs'; +import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; const PREFIX_ADDRESS = '0200'; diff --git a/contracts/utils/src/test/utils/index.ts b/contracts/utils/src/test/utils/index.ts new file mode 100644 index 00000000..2668cc79 --- /dev/null +++ b/contracts/utils/src/test/utils/index.ts @@ -0,0 +1,4 @@ +export { useCircuitContext as circuitContext } from './test'; +export { + pad, encodeToPK, encodeToAddress, createEitherTestUser, createEitherTestContractAddress, ZERO_KEY, ZERO_ADDRESS +} from './address'; diff --git a/contracts/utils/contract/src/witnesses/index.ts b/contracts/utils/src/witnesses/index.ts similarity index 100% rename from contracts/utils/contract/src/witnesses/index.ts rename to contracts/utils/src/witnesses/index.ts From 1d8480c0364a95494fd3104b168dc6529386a8ed Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 02:07:16 -0500 Subject: [PATCH 258/282] fix structure --- contracts/utils/{ => contract}/package.json | 0 contracts/utils/{ => contract}/src/Initializable.compact | 0 contracts/utils/{ => contract}/src/MockUtils.compact | 0 contracts/utils/{ => contract}/src/Pausable.compact | 0 contracts/utils/{ => contract}/src/Utils.compact | 0 .../utils/{ => contract}/src/test/Initializable.test.ts | 0 contracts/utils/{ => contract}/src/test/Pausable.test.ts | 0 .../utils/{ => contract}/src/test/UtilsSimulator.ts | 0 .../src/test/mocks/MockInitializable.compact | 0 .../{ => contract}/src/test/mocks/MockPausable.compact | 0 .../{ => contract}/src/test/mocks/MockUtils.compact | 0 .../src/test/simulators/InitializableSimulator.ts | 0 .../src/test/simulators/PausableSimulator.ts | 0 .../{ => contract}/src/test/simulators/UtilsSimulator.ts | 0 contracts/utils/{ => contract}/src/test/types/test.ts | 0 contracts/utils/{ => contract}/src/test/utils.test.ts | 9 +++++++++ contracts/utils/{ => contract}/src/test/utils/address.ts | 0 contracts/utils/{ => contract}/src/test/utils/index.ts | 0 contracts/utils/{ => contract}/src/test/utils/test.ts | 0 .../src/witnesses/InitializableWitnesses.ts | 0 .../{ => contract}/src/witnesses/PausableWitnesses.ts | 0 .../utils/{ => contract}/src/witnesses/UtilsWitnesses.ts | 0 contracts/utils/{ => contract}/src/witnesses/index.ts | 0 contracts/utils/{ => contract}/tsconfig.build.json | 0 contracts/utils/{ => contract}/tsconfig.json | 0 25 files changed, 9 insertions(+) rename contracts/utils/{ => contract}/package.json (100%) rename contracts/utils/{ => contract}/src/Initializable.compact (100%) rename contracts/utils/{ => contract}/src/MockUtils.compact (100%) rename contracts/utils/{ => contract}/src/Pausable.compact (100%) rename contracts/utils/{ => contract}/src/Utils.compact (100%) rename contracts/utils/{ => contract}/src/test/Initializable.test.ts (100%) rename contracts/utils/{ => contract}/src/test/Pausable.test.ts (100%) rename contracts/utils/{ => contract}/src/test/UtilsSimulator.ts (100%) rename contracts/utils/{ => contract}/src/test/mocks/MockInitializable.compact (100%) rename contracts/utils/{ => contract}/src/test/mocks/MockPausable.compact (100%) rename contracts/utils/{ => contract}/src/test/mocks/MockUtils.compact (100%) rename contracts/utils/{ => contract}/src/test/simulators/InitializableSimulator.ts (100%) rename contracts/utils/{ => contract}/src/test/simulators/PausableSimulator.ts (100%) rename contracts/utils/{ => contract}/src/test/simulators/UtilsSimulator.ts (100%) rename contracts/utils/{ => contract}/src/test/types/test.ts (100%) rename contracts/utils/{ => contract}/src/test/utils.test.ts (86%) rename contracts/utils/{ => contract}/src/test/utils/address.ts (100%) rename contracts/utils/{ => contract}/src/test/utils/index.ts (100%) rename contracts/utils/{ => contract}/src/test/utils/test.ts (100%) rename contracts/utils/{ => contract}/src/witnesses/InitializableWitnesses.ts (100%) rename contracts/utils/{ => contract}/src/witnesses/PausableWitnesses.ts (100%) rename contracts/utils/{ => contract}/src/witnesses/UtilsWitnesses.ts (100%) rename contracts/utils/{ => contract}/src/witnesses/index.ts (100%) rename contracts/utils/{ => contract}/tsconfig.build.json (100%) rename contracts/utils/{ => contract}/tsconfig.json (100%) diff --git a/contracts/utils/package.json b/contracts/utils/contract/package.json similarity index 100% rename from contracts/utils/package.json rename to contracts/utils/contract/package.json diff --git a/contracts/utils/src/Initializable.compact b/contracts/utils/contract/src/Initializable.compact similarity index 100% rename from contracts/utils/src/Initializable.compact rename to contracts/utils/contract/src/Initializable.compact diff --git a/contracts/utils/src/MockUtils.compact b/contracts/utils/contract/src/MockUtils.compact similarity index 100% rename from contracts/utils/src/MockUtils.compact rename to contracts/utils/contract/src/MockUtils.compact diff --git a/contracts/utils/src/Pausable.compact b/contracts/utils/contract/src/Pausable.compact similarity index 100% rename from contracts/utils/src/Pausable.compact rename to contracts/utils/contract/src/Pausable.compact diff --git a/contracts/utils/src/Utils.compact b/contracts/utils/contract/src/Utils.compact similarity index 100% rename from contracts/utils/src/Utils.compact rename to contracts/utils/contract/src/Utils.compact diff --git a/contracts/utils/src/test/Initializable.test.ts b/contracts/utils/contract/src/test/Initializable.test.ts similarity index 100% rename from contracts/utils/src/test/Initializable.test.ts rename to contracts/utils/contract/src/test/Initializable.test.ts diff --git a/contracts/utils/src/test/Pausable.test.ts b/contracts/utils/contract/src/test/Pausable.test.ts similarity index 100% rename from contracts/utils/src/test/Pausable.test.ts rename to contracts/utils/contract/src/test/Pausable.test.ts diff --git a/contracts/utils/src/test/UtilsSimulator.ts b/contracts/utils/contract/src/test/UtilsSimulator.ts similarity index 100% rename from contracts/utils/src/test/UtilsSimulator.ts rename to contracts/utils/contract/src/test/UtilsSimulator.ts diff --git a/contracts/utils/src/test/mocks/MockInitializable.compact b/contracts/utils/contract/src/test/mocks/MockInitializable.compact similarity index 100% rename from contracts/utils/src/test/mocks/MockInitializable.compact rename to contracts/utils/contract/src/test/mocks/MockInitializable.compact diff --git a/contracts/utils/src/test/mocks/MockPausable.compact b/contracts/utils/contract/src/test/mocks/MockPausable.compact similarity index 100% rename from contracts/utils/src/test/mocks/MockPausable.compact rename to contracts/utils/contract/src/test/mocks/MockPausable.compact diff --git a/contracts/utils/src/test/mocks/MockUtils.compact b/contracts/utils/contract/src/test/mocks/MockUtils.compact similarity index 100% rename from contracts/utils/src/test/mocks/MockUtils.compact rename to contracts/utils/contract/src/test/mocks/MockUtils.compact diff --git a/contracts/utils/src/test/simulators/InitializableSimulator.ts b/contracts/utils/contract/src/test/simulators/InitializableSimulator.ts similarity index 100% rename from contracts/utils/src/test/simulators/InitializableSimulator.ts rename to contracts/utils/contract/src/test/simulators/InitializableSimulator.ts diff --git a/contracts/utils/src/test/simulators/PausableSimulator.ts b/contracts/utils/contract/src/test/simulators/PausableSimulator.ts similarity index 100% rename from contracts/utils/src/test/simulators/PausableSimulator.ts rename to contracts/utils/contract/src/test/simulators/PausableSimulator.ts diff --git a/contracts/utils/src/test/simulators/UtilsSimulator.ts b/contracts/utils/contract/src/test/simulators/UtilsSimulator.ts similarity index 100% rename from contracts/utils/src/test/simulators/UtilsSimulator.ts rename to contracts/utils/contract/src/test/simulators/UtilsSimulator.ts diff --git a/contracts/utils/src/test/types/test.ts b/contracts/utils/contract/src/test/types/test.ts similarity index 100% rename from contracts/utils/src/test/types/test.ts rename to contracts/utils/contract/src/test/types/test.ts diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/contract/src/test/utils.test.ts similarity index 86% rename from contracts/utils/src/test/utils.test.ts rename to contracts/utils/contract/src/test/utils.test.ts index 1398d4d9..b55f2ac5 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/contract/src/test/utils.test.ts @@ -3,11 +3,15 @@ import { UtilsSimulator } from './simulators/UtilsSimulator.js'; import * as contractUtils from './utils/address.js'; const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); +<<<<<<< HEAD:contracts/utils/src/test/utils.test.ts const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); const SOME_CONTRACT = contractUtils.createEitherTestContractAddress('SOME_CONTRACT'); const OTHER_CONTRACT = contractUtils.createEitherTestContractAddress('OTHER_CONTRACT'); +======= +const SOME_CONTRACT = contractUtils.createEitherTestContractAddress('SOME_CONTRACT'); +>>>>>>> 0aeb3f9 (fix structure):contracts/utils/contract/src/test/utils.test.ts const EMPTY_STRING = ''; @@ -25,6 +29,7 @@ describe('Utils', () => { }); it('should not return zero for nonzero addresses', () => { +<<<<<<< HEAD:contracts/utils/src/test/utils.test.ts expect(contract.isKeyOrAddressZero(Z_SOME_KEY)).toBe(false); expect(contract.isKeyOrAddressZero(SOME_CONTRACT)).toBe(false); }); @@ -90,6 +95,10 @@ describe('Utils', () => { describe('emptyString', () => { it('should return the empty string', () => { expect(contract.emptyString()).toBe(EMPTY_STRING); +======= + expect(contract.isZero(Z_SOME_KEY)).toBeFalsy; + expect(contract.isZero(SOME_CONTRACT)).toBeFalsy; +>>>>>>> 0aeb3f9 (fix structure):contracts/utils/contract/src/test/utils.test.ts }); }); }); diff --git a/contracts/utils/src/test/utils/address.ts b/contracts/utils/contract/src/test/utils/address.ts similarity index 100% rename from contracts/utils/src/test/utils/address.ts rename to contracts/utils/contract/src/test/utils/address.ts diff --git a/contracts/utils/src/test/utils/index.ts b/contracts/utils/contract/src/test/utils/index.ts similarity index 100% rename from contracts/utils/src/test/utils/index.ts rename to contracts/utils/contract/src/test/utils/index.ts diff --git a/contracts/utils/src/test/utils/test.ts b/contracts/utils/contract/src/test/utils/test.ts similarity index 100% rename from contracts/utils/src/test/utils/test.ts rename to contracts/utils/contract/src/test/utils/test.ts diff --git a/contracts/utils/src/witnesses/InitializableWitnesses.ts b/contracts/utils/contract/src/witnesses/InitializableWitnesses.ts similarity index 100% rename from contracts/utils/src/witnesses/InitializableWitnesses.ts rename to contracts/utils/contract/src/witnesses/InitializableWitnesses.ts diff --git a/contracts/utils/src/witnesses/PausableWitnesses.ts b/contracts/utils/contract/src/witnesses/PausableWitnesses.ts similarity index 100% rename from contracts/utils/src/witnesses/PausableWitnesses.ts rename to contracts/utils/contract/src/witnesses/PausableWitnesses.ts diff --git a/contracts/utils/src/witnesses/UtilsWitnesses.ts b/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts similarity index 100% rename from contracts/utils/src/witnesses/UtilsWitnesses.ts rename to contracts/utils/contract/src/witnesses/UtilsWitnesses.ts diff --git a/contracts/utils/src/witnesses/index.ts b/contracts/utils/contract/src/witnesses/index.ts similarity index 100% rename from contracts/utils/src/witnesses/index.ts rename to contracts/utils/contract/src/witnesses/index.ts diff --git a/contracts/utils/tsconfig.build.json b/contracts/utils/contract/tsconfig.build.json similarity index 100% rename from contracts/utils/tsconfig.build.json rename to contracts/utils/contract/tsconfig.build.json diff --git a/contracts/utils/tsconfig.json b/contracts/utils/contract/tsconfig.json similarity index 100% rename from contracts/utils/tsconfig.json rename to contracts/utils/contract/tsconfig.json From 13bf2d85edf848ac629d5288fe6ce46a911f925f Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 02:24:56 -0500 Subject: [PATCH 259/282] improve circuit name --- contracts/utils/contract/src/MockUtils.compact | 4 ++-- contracts/utils/contract/src/test/UtilsSimulator.ts | 4 ++-- contracts/utils/contract/src/test/utils.test.ts | 12 ++---------- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/contracts/utils/contract/src/MockUtils.compact b/contracts/utils/contract/src/MockUtils.compact index 479a1fa2..f2263768 100644 --- a/contracts/utils/contract/src/MockUtils.compact +++ b/contracts/utils/contract/src/MockUtils.compact @@ -8,6 +8,6 @@ import Utils prefix Utils_; export { ZswapCoinPublicKey, ContractAddress, Either }; -export pure circuit isZero(keyOrAddress: Either): Boolean { - return Utils_isZero(keyOrAddress); +export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { + return Utils_isKeyOrAddressZero(keyOrAddress); } diff --git a/contracts/utils/contract/src/test/UtilsSimulator.ts b/contracts/utils/contract/src/test/UtilsSimulator.ts index 98190e5c..c55c802f 100644 --- a/contracts/utils/contract/src/test/UtilsSimulator.ts +++ b/contracts/utils/contract/src/test/UtilsSimulator.ts @@ -88,7 +88,7 @@ export class UtilsContractSimulator * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @returns Returns true if `keyOrAddress` is zero. */ - public isZero(keyOrAddress: Either): boolean { - return this.contract.circuits.isZero(this.circuitContext, keyOrAddress).result; + public isKeyOrAddressZero(keyOrAddress: Either): boolean { + return this.contract.circuits.isKeyOrAddressZero(this.circuitContext, keyOrAddress).result; } } diff --git a/contracts/utils/contract/src/test/utils.test.ts b/contracts/utils/contract/src/test/utils.test.ts index b55f2ac5..7ff600f7 100644 --- a/contracts/utils/contract/src/test/utils.test.ts +++ b/contracts/utils/contract/src/test/utils.test.ts @@ -3,15 +3,11 @@ import { UtilsSimulator } from './simulators/UtilsSimulator.js'; import * as contractUtils from './utils/address.js'; const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); -<<<<<<< HEAD:contracts/utils/src/test/utils.test.ts const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); const SOME_CONTRACT = contractUtils.createEitherTestContractAddress('SOME_CONTRACT'); const OTHER_CONTRACT = contractUtils.createEitherTestContractAddress('OTHER_CONTRACT'); -======= -const SOME_CONTRACT = contractUtils.createEitherTestContractAddress('SOME_CONTRACT'); ->>>>>>> 0aeb3f9 (fix structure):contracts/utils/contract/src/test/utils.test.ts const EMPTY_STRING = ''; @@ -29,7 +25,6 @@ describe('Utils', () => { }); it('should not return zero for nonzero addresses', () => { -<<<<<<< HEAD:contracts/utils/src/test/utils.test.ts expect(contract.isKeyOrAddressZero(Z_SOME_KEY)).toBe(false); expect(contract.isKeyOrAddressZero(SOME_CONTRACT)).toBe(false); }); @@ -74,7 +69,8 @@ describe('Utils', () => { describe('isKeyZero', () => { it('should return zero for the zero address', () => { - expect(contract.isKeyZero(contractUtils.ZERO_KEY.left)).toBe(true); + expect(contract.isKeyOrAddressZero(contractUtils.ZERO_KEY)).toBeTruthy; + expect(contract.isKeyOrAddressZero(contractUtils.ZERO_ADDRESS)).toBeTruthy; }); it('should not return zero for nonzero addresses', () => { @@ -95,10 +91,6 @@ describe('Utils', () => { describe('emptyString', () => { it('should return the empty string', () => { expect(contract.emptyString()).toBe(EMPTY_STRING); -======= - expect(contract.isZero(Z_SOME_KEY)).toBeFalsy; - expect(contract.isZero(SOME_CONTRACT)).toBeFalsy; ->>>>>>> 0aeb3f9 (fix structure):contracts/utils/contract/src/test/utils.test.ts }); }); }); From 0bfdee697ef8e2aa16097d580f55f3657200b80c Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:43:45 -0500 Subject: [PATCH 260/282] add mock --- .../src/witnesses/MockInitializable.compact | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 contracts/utils/contract/src/witnesses/MockInitializable.compact diff --git a/contracts/utils/contract/src/witnesses/MockInitializable.compact b/contracts/utils/contract/src/witnesses/MockInitializable.compact new file mode 100644 index 00000000..d670f6d9 --- /dev/null +++ b/contracts/utils/contract/src/witnesses/MockInitializable.compact @@ -0,0 +1,14 @@ +pragma language_version >= 0.14.0; + +import CompactStandardLibrary; +import Initializable prefix Initializable_; + +export { Initializable_state, Initializable_STATE }; + +export circuit initialize(): [] { + return Initializable_initialize(); +} + +export circuit isInitialized(): Boolean { + return Initializable_isInitialized(); +} From 3a3e49478bcce0c4b4c5bbab0d1a3cc56c67b4a0 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:46:46 -0500 Subject: [PATCH 261/282] fix simulator --- .../src/test/InitializableSimulator.ts | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 contracts/initializable/contract/src/test/InitializableSimulator.ts diff --git a/contracts/initializable/contract/src/test/InitializableSimulator.ts b/contracts/initializable/contract/src/test/InitializableSimulator.ts new file mode 100644 index 00000000..9857fa59 --- /dev/null +++ b/contracts/initializable/contract/src/test/InitializableSimulator.ts @@ -0,0 +1,80 @@ +import { type CircuitContext, type ContractState, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; +import { Contract as MockInitializable, type Ledger, ledger } from '../artifacts/MockInitializable/contract/index.cjs'; +import type { IContractSimulator } from './types'; +import { InitializablePrivateState, InitializableWitnesses } from '../witnesses'; + +/** + * @description A simulator implementation of an utils contract for testing purposes. + * @template P - The private state type, fixed to UtilsPrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class InitializableSimulator + implements IContractSimulator +{ + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockInitializable; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor() { + this.contract = new MockInitializable( + InitializableWitnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)) + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type UtilsPrivateState. + */ + public getCurrentPrivateState(): InitializablePrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + + public initialize() { + this.circuitContext = this.contract.impureCircuits.initialize(this.circuitContext).context; + } + + public isInitialized(): boolean { + return this.contract.impureCircuits.isInitialized(this.circuitContext).result; + } +} From 34ab0fdde66a0beb9e473709f06c3e13850bf675 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:47:45 -0500 Subject: [PATCH 262/282] add witnesses dir --- .../contract/src/witnesses/InitializableWitnesses.ts | 3 +++ contracts/initializable/contract/src/witnesses/index.ts | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 contracts/initializable/contract/src/witnesses/InitializableWitnesses.ts create mode 100644 contracts/initializable/contract/src/witnesses/index.ts diff --git a/contracts/initializable/contract/src/witnesses/InitializableWitnesses.ts b/contracts/initializable/contract/src/witnesses/InitializableWitnesses.ts new file mode 100644 index 00000000..9d99cd04 --- /dev/null +++ b/contracts/initializable/contract/src/witnesses/InitializableWitnesses.ts @@ -0,0 +1,3 @@ +// This is how we type an empty object. +export type InitializablePrivateState = Record; +export const InitializableWitnesses = {}; diff --git a/contracts/initializable/contract/src/witnesses/index.ts b/contracts/initializable/contract/src/witnesses/index.ts new file mode 100644 index 00000000..d27dd4c3 --- /dev/null +++ b/contracts/initializable/contract/src/witnesses/index.ts @@ -0,0 +1,2 @@ +export * from '../artifacts/initializable/contract/index.cjs'; +export * from './InitializableWitnesses'; From 68369b1357dd7acb7c8298535772370c29fcf50c Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:48:03 -0500 Subject: [PATCH 263/282] add testing pattern --- .../contract/src/test/types/index.ts | 1 + .../contract/src/test/types/test.ts | 23 +++++++ .../contract/src/test/utils/index.ts | 1 + .../contract/src/test/utils/test.ts | 67 +++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 contracts/initializable/contract/src/test/types/index.ts create mode 100644 contracts/initializable/contract/src/test/types/test.ts create mode 100644 contracts/initializable/contract/src/test/utils/index.ts create mode 100644 contracts/initializable/contract/src/test/utils/test.ts diff --git a/contracts/initializable/contract/src/test/types/index.ts b/contracts/initializable/contract/src/test/types/index.ts new file mode 100644 index 00000000..db642b5e --- /dev/null +++ b/contracts/initializable/contract/src/test/types/index.ts @@ -0,0 +1 @@ +export type { IContractSimulator } from './test'; diff --git a/contracts/initializable/contract/src/test/types/test.ts b/contracts/initializable/contract/src/test/types/test.ts new file mode 100644 index 00000000..10fb6c98 --- /dev/null +++ b/contracts/initializable/contract/src/test/types/test.ts @@ -0,0 +1,23 @@ +import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; + +/** + * Generic interface for mock contract implementations. + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + */ +export interface IContractSimulator { + /** The contract's deployed address. */ + readonly contractAddress: string; + + /** The current circuit context. */ + circuitContext: CircuitContext

; + + /** Retrieves the current ledger state. */ + getCurrentPublicState(): L; + + /** Retrieves the current private state. */ + getCurrentPrivateState(): P; + + /** Retrieves the current contract state. */ + getCurrentContractState(): ContractState; +} diff --git a/contracts/initializable/contract/src/test/utils/index.ts b/contracts/initializable/contract/src/test/utils/index.ts new file mode 100644 index 00000000..14e02ef2 --- /dev/null +++ b/contracts/initializable/contract/src/test/utils/index.ts @@ -0,0 +1 @@ +export { useCircuitContext as circuitContext } from './test'; diff --git a/contracts/initializable/contract/src/test/utils/test.ts b/contracts/initializable/contract/src/test/utils/test.ts new file mode 100644 index 00000000..5a9e5837 --- /dev/null +++ b/contracts/initializable/contract/src/test/utils/test.ts @@ -0,0 +1,67 @@ +import { + type CircuitContext, + type CoinPublicKey, + type ContractAddress, + type ContractState, + QueryContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import type { IContractSimulator } from '../types'; + +/** + * Constructs a `CircuitContext` from the given state and sender information. + * + * This is typically used at runtime to provide the necessary context + * for executing circuits, including contract state, private state, + * sender identity, and transaction data. + * + * @template P - The type of the contract's private state. + * @param privateState - The current private state of the contract. + * @param contractState - The full contract state, including public and private data. + * @param sender - The public key of the sender (used in the circuit). + * @param contractAddress - The address of the deployed contract. + * @returns A fully populated `CircuitContext` for circuit execution. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContext

( + privateState: P, + contractState: ContractState, + sender: CoinPublicKey, + contractAddress: ContractAddress, +): CircuitContext

{ + return { + originalState: contractState, + currentPrivateState: privateState, + transactionContext: new QueryContext(contractState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} + +/** + * Prepares a new `CircuitContext` using the given sender and contract. + * + * Useful for mocking or updating the circuit context with a custom sender. + * + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + * @template C - The specific type of the contract implementing `MockContract`. + * @param contract - The contract instance implementing `MockContract`. + * @param sender - The public key to set as the sender in the new circuit context. + * @returns A new `CircuitContext` with the sender and updated context values. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContextSender>( + contract: C, + sender: CoinPublicKey, +): CircuitContext

{ + const currentPrivateState = contract.getCurrentPrivateState(); + const originalState = contract.getCurrentContractState(); + const contractAddress = contract.contractAddress; + + return { + originalState, + currentPrivateState, + transactionContext: new QueryContext(originalState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} From 80ca657066829b2555b7f4a6be1eeb15de905c11 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:50:20 -0500 Subject: [PATCH 264/282] improve comments --- .../contract/src/test/InitializableSimulator.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/contracts/initializable/contract/src/test/InitializableSimulator.ts b/contracts/initializable/contract/src/test/InitializableSimulator.ts index 9857fa59..6778bfa0 100644 --- a/contracts/initializable/contract/src/test/InitializableSimulator.ts +++ b/contracts/initializable/contract/src/test/InitializableSimulator.ts @@ -70,10 +70,18 @@ export class InitializableSimulator return this.circuitContext.originalState; } + /** + * @description Initializes the state. + * @returns None. + */ public initialize() { this.circuitContext = this.contract.impureCircuits.initialize(this.circuitContext).context; } + /** + * @description Returns true if the state is initialized. + * @returns {boolean} - whether the contract has been initialized. + */ public isInitialized(): boolean { return this.contract.impureCircuits.isInitialized(this.circuitContext).result; } From 62eeae940df1ff74125950410bb858f1b711c993 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Apr 2025 16:52:00 -0500 Subject: [PATCH 265/282] tidy up simulator --- .../initializable/contract/src/test/InitializableSimulator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/initializable/contract/src/test/InitializableSimulator.ts b/contracts/initializable/contract/src/test/InitializableSimulator.ts index 6778bfa0..89402a19 100644 --- a/contracts/initializable/contract/src/test/InitializableSimulator.ts +++ b/contracts/initializable/contract/src/test/InitializableSimulator.ts @@ -80,7 +80,7 @@ export class InitializableSimulator /** * @description Returns true if the state is initialized. - * @returns {boolean} - whether the contract has been initialized. + * @returns Whether the contract has been initialized. */ public isInitialized(): boolean { return this.contract.impureCircuits.isInitialized(this.circuitContext).result; From d11e3812c3091e1f5c7bf39241d5b7ffd38d320b Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 8 Apr 2025 14:48:38 -0500 Subject: [PATCH 266/282] erc20 unshielded (#1) * test: adding more tests in ERC20 contract * catch mint overflow to output a more readable error msg * add overflow tests * fix test assertions * add initial module doc * remove contract dir * re-add erc20 * use utils zero address check in erc20 * fix sim export * remove file * remove unused type * add line * set metadata as sealed * add initializer comment * add return comment to initializer --------- Co-authored-by: 0xisk --- contracts/erc20/.eslintignore | 1 + contracts/erc20/.eslintrc.cjs | 30 ++ contracts/erc20/jest.config.ts | 28 ++ contracts/erc20/js-resolver.cjs | 16 + contracts/erc20/package.json | 32 ++ contracts/erc20/src/ERC20.compact | 345 +++++++++++++ contracts/erc20/src/test/erc20.test.ts | 471 ++++++++++++++++++ .../erc20/src/test/mocks/MockERC20.compact | 106 ++++ .../src/test/simulators/ERC20Simulator.ts | 299 +++++++++++ contracts/erc20/src/test/simulators/index.ts | 1 + .../contract => erc20}/src/test/types/test.ts | 0 contracts/erc20/src/test/utils/address.ts | 78 +++ contracts/erc20/src/test/utils/index.ts | 2 + .../contract => erc20}/src/test/utils/test.ts | 0 .../erc20/src/witnesses/ERC20Witnesses.ts | 3 + contracts/erc20/src/witnesses/index.ts | 2 + .../contract => erc20}/tsconfig.build.json | 0 contracts/erc20/tsconfig.json | 21 + .../initializable/src/Initializable.compact | 33 ++ .../src}/MockInitializable.compact | 0 .../src/test/InitializableSimulator.ts | 0 .../src/test/initializable.test.ts | 32 ++ .../{contract => }/src/test/types/index.ts | 0 .../{contract => }/src/test/types/test.ts | 0 .../{contract => }/src/test/utils/index.ts | 0 .../{contract => }/src/test/utils/test.ts | 0 .../src/witnesses/InitializableWitnesses.ts | 0 .../{contract => }/src/witnesses/index.ts | 0 contracts/initializable/tsconfig.build.json | 5 + contracts/initializable/tsconfig.json | 21 + contracts/utils/{contract => }/package.json | 0 .../{contract => }/src/Initializable.compact | 0 .../{contract => }/src/MockUtils.compact | 0 .../utils/{contract => }/src/Pausable.compact | 0 .../utils/{contract => }/src/Utils.compact | 0 .../src/test/Initializable.test.ts | 0 .../{contract => }/src/test/Pausable.test.ts | 0 .../{contract => }/src/test/UtilsSimulator.ts | 0 .../src/test/mocks/MockInitializable.compact | 0 .../src/test/mocks/MockPausable.compact | 0 .../src/test/mocks/MockUtils.compact | 0 .../test/simulators/InitializableSimulator.ts | 0 .../src/test/simulators/PausableSimulator.ts | 0 .../src/test/simulators/UtilsSimulator.ts | 0 contracts/utils/src/test/types/index.ts | 1 + contracts/utils/src/test/types/test.ts | 23 + .../{contract => }/src/test/utils.test.ts | 0 .../{contract => }/src/test/utils/address.ts | 0 .../{contract => }/src/test/utils/index.ts | 0 contracts/utils/src/test/utils/test.ts | 67 +++ .../src/witnesses/InitializableWitnesses.ts | 0 .../src/witnesses/MockInitializable.compact | 14 + .../src/witnesses/PausableWitnesses.ts | 0 .../src/witnesses/UtilsWitnesses.ts | 0 .../{contract => }/src/witnesses/index.ts | 0 contracts/utils/tsconfig.build.json | 5 + contracts/utils/{contract => }/tsconfig.json | 0 57 files changed, 1636 insertions(+) create mode 100644 contracts/erc20/.eslintignore create mode 100644 contracts/erc20/.eslintrc.cjs create mode 100644 contracts/erc20/jest.config.ts create mode 100644 contracts/erc20/js-resolver.cjs create mode 100644 contracts/erc20/package.json create mode 100644 contracts/erc20/src/ERC20.compact create mode 100644 contracts/erc20/src/test/erc20.test.ts create mode 100644 contracts/erc20/src/test/mocks/MockERC20.compact create mode 100644 contracts/erc20/src/test/simulators/ERC20Simulator.ts create mode 100644 contracts/erc20/src/test/simulators/index.ts rename contracts/{utils/contract => erc20}/src/test/types/test.ts (100%) create mode 100644 contracts/erc20/src/test/utils/address.ts create mode 100644 contracts/erc20/src/test/utils/index.ts rename contracts/{utils/contract => erc20}/src/test/utils/test.ts (100%) create mode 100644 contracts/erc20/src/witnesses/ERC20Witnesses.ts create mode 100644 contracts/erc20/src/witnesses/index.ts rename contracts/{utils/contract => erc20}/tsconfig.build.json (100%) create mode 100644 contracts/erc20/tsconfig.json create mode 100644 contracts/initializable/src/Initializable.compact rename contracts/{utils/contract/src/witnesses => initializable/src}/MockInitializable.compact (100%) rename contracts/initializable/{contract => }/src/test/InitializableSimulator.ts (100%) create mode 100644 contracts/initializable/src/test/initializable.test.ts rename contracts/initializable/{contract => }/src/test/types/index.ts (100%) rename contracts/initializable/{contract => }/src/test/types/test.ts (100%) rename contracts/initializable/{contract => }/src/test/utils/index.ts (100%) rename contracts/initializable/{contract => }/src/test/utils/test.ts (100%) rename contracts/initializable/{contract => }/src/witnesses/InitializableWitnesses.ts (100%) rename contracts/initializable/{contract => }/src/witnesses/index.ts (100%) create mode 100644 contracts/initializable/tsconfig.build.json create mode 100644 contracts/initializable/tsconfig.json rename contracts/utils/{contract => }/package.json (100%) rename contracts/utils/{contract => }/src/Initializable.compact (100%) rename contracts/utils/{contract => }/src/MockUtils.compact (100%) rename contracts/utils/{contract => }/src/Pausable.compact (100%) rename contracts/utils/{contract => }/src/Utils.compact (100%) rename contracts/utils/{contract => }/src/test/Initializable.test.ts (100%) rename contracts/utils/{contract => }/src/test/Pausable.test.ts (100%) rename contracts/utils/{contract => }/src/test/UtilsSimulator.ts (100%) rename contracts/utils/{contract => }/src/test/mocks/MockInitializable.compact (100%) rename contracts/utils/{contract => }/src/test/mocks/MockPausable.compact (100%) rename contracts/utils/{contract => }/src/test/mocks/MockUtils.compact (100%) rename contracts/utils/{contract => }/src/test/simulators/InitializableSimulator.ts (100%) rename contracts/utils/{contract => }/src/test/simulators/PausableSimulator.ts (100%) rename contracts/utils/{contract => }/src/test/simulators/UtilsSimulator.ts (100%) create mode 100644 contracts/utils/src/test/types/index.ts create mode 100644 contracts/utils/src/test/types/test.ts rename contracts/utils/{contract => }/src/test/utils.test.ts (100%) rename contracts/utils/{contract => }/src/test/utils/address.ts (100%) rename contracts/utils/{contract => }/src/test/utils/index.ts (100%) create mode 100644 contracts/utils/src/test/utils/test.ts rename contracts/utils/{contract => }/src/witnesses/InitializableWitnesses.ts (100%) create mode 100644 contracts/utils/src/witnesses/MockInitializable.compact rename contracts/utils/{contract => }/src/witnesses/PausableWitnesses.ts (100%) rename contracts/utils/{contract => }/src/witnesses/UtilsWitnesses.ts (100%) rename contracts/utils/{contract => }/src/witnesses/index.ts (100%) create mode 100644 contracts/utils/tsconfig.build.json rename contracts/utils/{contract => }/tsconfig.json (100%) diff --git a/contracts/erc20/.eslintignore b/contracts/erc20/.eslintignore new file mode 100644 index 00000000..327555cd --- /dev/null +++ b/contracts/erc20/.eslintignore @@ -0,0 +1 @@ +src/artifacts diff --git a/contracts/erc20/.eslintrc.cjs b/contracts/erc20/.eslintrc.cjs new file mode 100644 index 00000000..581f1d49 --- /dev/null +++ b/contracts/erc20/.eslintrc.cjs @@ -0,0 +1,30 @@ +module.exports = { + env: { + browser: true, + es2021: true, + node: true, + jest: true, + }, + extends: [ + 'standard-with-typescript', + 'plugin:prettier/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + ], + overrides: [], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['tsconfig.json'], + }, + rules: { + '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 + '@typescript-eslint/no-floating-promises': 'warn', + '@typescript-eslint/promise-function-async': 'off', + '@typescript-eslint/no-redeclare': 'off', + '@typescript-eslint/no-invalid-void-type': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/consistent-type-definitions': 'off' + }, +}; diff --git a/contracts/erc20/jest.config.ts b/contracts/erc20/jest.config.ts new file mode 100644 index 00000000..3cbccc1b --- /dev/null +++ b/contracts/erc20/jest.config.ts @@ -0,0 +1,28 @@ +import type { Config } from "@jest/types"; + +const config: Config.InitialOptions = { + preset: "ts-jest/presets/default-esm", + testEnvironment: "node", + verbose: true, + roots: [""], + modulePaths: [""], + passWithNoTests: false, + testMatch: ["**/*.test.ts"], + extensionsToTreatAsEsm: [".ts"], + collectCoverage: true, + resolver: '/js-resolver.cjs', + coverageThreshold: { + global: { + branches: 50, + functions: 50, + lines: 50, + }, + }, + reporters: [ + "default", + ["jest-junit", { outputDirectory: "reports", outputName: "report.xml" }], + ["jest-html-reporters", { publicPath: "reports", filename: "report.html" }], + ], +}; + +export default config; diff --git a/contracts/erc20/js-resolver.cjs b/contracts/erc20/js-resolver.cjs new file mode 100644 index 00000000..cc9ed285 --- /dev/null +++ b/contracts/erc20/js-resolver.cjs @@ -0,0 +1,16 @@ +const jsResolver = (path, options) => { + const jsExtRegex = /\.js$/i + const resolver = options.defaultResolver + if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { + const newPath = path.replace(jsExtRegex, '.ts'); + try { + return resolver(newPath, options) + } catch { + // use default resolver + } + } + + return resolver(path, options) +} + +module.exports = jsResolver diff --git a/contracts/erc20/package.json b/contracts/erc20/package.json new file mode 100644 index 00000000..d914daf0 --- /dev/null +++ b/contracts/erc20/package.json @@ -0,0 +1,32 @@ +{ + "name": "@openzeppelin-midnight-contracts/erc20-contract", + "type": "module", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "scripts": { + "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", + "test": "NODE_OPTIONS=--experimental-vm-modules jest", + "prepack": "yarn build", + "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/ERC20.compact ./dist", + "lint": "eslint src", + "typecheck": "tsc -p tsconfig.json --noEmit" + }, + "dependencies": { + "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" + }, + "devDependencies": { + "@midnight-ntwrk/compact": "workspace:*", + "eslint": "^8.52.0", + "jest": "^29.7.0", + "typescript": "^5.2.2" + } +} diff --git a/contracts/erc20/src/ERC20.compact b/contracts/erc20/src/ERC20.compact new file mode 100644 index 00000000..0f520112 --- /dev/null +++ b/contracts/erc20/src/ERC20.compact @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.14.0; + +/** + * @module ERC20 + * @description An unshielded ERC20 library. + * + * @notice One notable difference regarding this implementation and the EIP20 spec + * consists of the token size. Uint<128> is used as the token size because Uint<256> + * cannot be supported. + * This is due to encoding limits on the midnight circuit backend: + * https://github.com/midnightntwrk/compactc/issues/929 + * + * @notice Further discussion and consideration required: + * + * - Consider changing the underscore in the internal methods to `unsafe` or + * adopting dot notation for prefixing imports. + * - Revise logic once contract-to-contract interactions are available on midnight. + * - Consider implementing an introspection mechanism for transfers to contracts. + * - Standardize which zero address to use (`ZswapCoinPublicKey` or `ContractAddress`). + */ +module ERC20 { + import CompactStandardLibrary; + import "../../node_modules/@openzeppelin-midnight-contracts/utils-contract/src/Utils" prefix Utils_; + + /// Public state + export sealed ledger _name: Maybe>; + export sealed ledger _symbol: Maybe>; + export sealed ledger _decimals: Uint<8>; + export ledger _totalSupply: Uint<128>; + export ledger _balances: Map, Uint<128>>; + export ledger _allowances: Map, Map, Uint<128>>>; + + /** + * @description Initializes the contract by setting the name, symbol, and decimals. + * @dev This MUST be called in the implementing contract's constructor. Failure to do so + * can lead to an irreparable contract. + * + * @param name_ - The name of the token. + * @param symbol_ - The symbol of the token. + * @param decimals_ - The number of decimals used to get the user representation. + * @return {[]} - None. + */ + export circuit initializer( + name_: Maybe>, + symbol_: Maybe>, + decimals_:Uint<8> + ): [] { + _name = name_; + _symbol = symbol_; + _decimals = decimals_; + } + + /** + * @description Returns the token name. + * + * @return {Maybe>} - The token name. + */ + export circuit name(): Maybe> { + return _name; + } + + /** + * @description Returns the symbol of the token. + * + * @return {Maybe>} - The token name. + */ + export circuit symbol(): Maybe> { + return _symbol; + } + + /** + * @description Returns the number of decimals used to get its user representation. + * + * @return {Uint<8>} - The account's token balance. + */ + export circuit decimals(): Uint<8> { + return _decimals; + } + + /** + * @description Returns the value of tokens in existence. + * + * @return {Uint<128>} - The total supply of tokens. + */ + export circuit totalSupply(): Uint<128> { + return _totalSupply; + } + + /** + * @description Returns the value of tokens owned by `account`. + * + * @dev Manually checks if `account` is a key in the map and returns 0 if it is not. + * + * @param {account} - The public key or contract address to query. + * @return {Uint<128>} - The account's token balance. + */ + export circuit balanceOf(account: Either): Uint<128> { + if (!_balances.member(account)) { + return 0; + } + + return _balances.lookup(account); + } + + /** + * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` + * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. + * + * @dev Manually checks if `owner` and `spender` are keys in the map and returns 0 if they are not. + * + * @param {owner} - The public key or contract address of approver. + * @param {spender} - The public key or contract address of spender. + * @return {Uint<128>} - The `spender`'s allowance over `owner`'s tokens. + */ + export circuit allowance( + owner: Either, + spender: Either + ): Uint<128> { + if (!_allowances.member(owner) || !_allowances.lookup(owner).member(spender)) { + return 0; + } + + return _allowances.lookup(owner).lookup(spender); + } + + /** + * @description Moves a `value` amount of tokens from the caller's account to `to`. + * + * @dev We need to get the caller address from contracts and handle the transfer appropriately. + * This should include a callback to ensure the contract can safely receive tokens. + * + * @param {to} - The recipient of the transfer, either a user or a contract. + * @param {value} - The amount to transfer. + * @return {Boolean} - As per the IERC20 spec, this MUST return true. + */ + export circuit transfer(to: Either, value: Uint<128>): Boolean { + // TMP - Waiting for contract-to-contract calls to handle `right` with contract address + const owner = left(own_public_key()); + _transfer(owner, to, value); + return true; + } + + /** + * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. + * `value` is the deducted from the caller's allowance. + * + * @dev We need to get the caller address from contracts and handle the transfer appropriately. + * This should include a callback to ensure the contract can safely receive tokens. + * + * @param {from} - The current owner of the tokens for the transfer, either a user or a contract. + * @param {to} - The recipient of the transfer, either a user or a contract. + * @param {value} - The amount to transfer. + * @return {Boolean} - As per the IERC20 spec, this MUST return true. + */ + export circuit transferFrom( + from: Either, + to: Either, + value: Uint<128> + ): Boolean { + // TMP - Waiting for contract-to-contract calls to handle `right` with contract address + const spender = left(own_public_key()); + _spendAllowance(from, spender, value); + _transfer(from, to, value); + return true; + } + + /** + * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. + * + * @param {spender} - The Zswap key or ContractAddress that may spend on behalf of the caller. + * @param {value} - The amount of tokens the `spender` may spend. + * @return {Boolean} - Returns a boolean value indicating whether the operation succeeded. + */ + export circuit approve(spender: Either, value: Uint<128>): Boolean { + // TMP - Waiting for contract-to-contract calls to handle `right` with contract address + const owner = left(own_public_key()); + _approve(owner, spender, value); + return true; + } + + /** + * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * @param {owner} - The owner of the tokens. + * @param {spender} - The spender of the tokens. + * @param {value} - The amount of tokens `spender` may spend on behalf of `owner`. + * @return {[]} - None. + */ + export circuit _approve( + owner: Either, + spender: Either, + value: Uint<128> + ): [] { + assert !Utils_isKeyOrAddressZero(owner) "ERC20: invalid owner"; + assert !Utils_isKeyOrAddressZero(spender) "ERC20: invalid spender"; + if (!_allowances.member(owner)) { + // If owner doesn't exist, create and insert a new sub-map directly + _allowances.insert(owner, default, Uint<128>>>); + } + _allowances.lookup(owner).insert(spender, value); + } + + /** + * @description Moves a `value` amount of tokens from `from` to `to`. + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * @param {from} - The owner of the tokens to transfer. + * @param {to} - The receipient of the transferred tokens. + * @param {value} - The amount of tokens to transfer. + * @return {[]} - None. + */ + export circuit _transfer( + from: Either, + to: Either, + value: Uint<128> + ): [] { + assert !Utils_isKeyOrAddressZero(from) "ERC20: invalid sender"; + assert !Utils_isKeyOrAddressZero(to) "ERC20: invalid receiver"; + + _update(from, to, value); + } + + /** + * @description Creates a `value` amount of tokens and assigns them to `account`, + * by transferring it from the zero address. Relies on the `update` mechanism. + * + * @param {account} - The recipient of tokens minted. + * @param {value} - The amount of tokens minted. + * @return {[]} - None. + */ + export circuit _mint( + account: Either, + value: Uint<128> + ): [] { + assert !Utils_isKeyOrAddressZero(account) "ERC20: invalid receiver"; + // Using the contract variant of 0 + // TODO: Look into if this matters + const zero_address = right(ContractAddress{ pad(32, "") }); + + _update(zero_address, account, value); + } + + /** + * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. + * Relies on the `_update` mechanism. + * + * @param {account} - The target owner of tokens to burn. + * @param {value} - The amount of tokens to burn. + * @return {[]} - None. + */ + export circuit _burn( + account: Either, + value: Uint<128> + ): [] { + assert !Utils_isKeyOrAddressZero(account) "ERC20: invalid sender"; + // Using the contract variant of 0 + // TODO: Look into if this matters + const zero_address = right(ContractAddress{ pad(32, "") }); + _update(account, zero_address, value); + } + + /** + * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` + * (or `to`) is the zero address. + * @dev Checks for a mint overflow in order to output a more readable error message. + * + * @param {from} - The original owner of the tokens moved (which is 0 if tokens are minted). + * @param {to} - The recipient of the tokens moved (which is 0 if tokens are burned). + * @param {value} - The amount of tokens moved from `from` to `to`. + * @return {[]} - None. + */ + export circuit _update( + from: Either, + to: Either, + value: Uint<128> + ): [] { + if (Utils_isKeyOrAddressZero(from)) { + // Mint + const MAX_UINT128 = 340282366920938463463374607431768211455; + assert MAX_UINT128 - _totalSupply >= value "ERC20: arithmetic overflow"; + + _totalSupply = _totalSupply + value as Uint<128>; + } else { + const fromBal = balanceOf(from); + assert fromBal >= value "ERC20: insufficient balance"; + _balances.insert(from, fromBal - value as Uint<128>); + } + + if (Utils_isKeyOrAddressZero(to)) { + // Burn + _totalSupply = _totalSupply - value as Uint<128>; + } else { + const toBal = balanceOf(to); + _balances.insert(to, toBal + value as Uint<128>); + } + } + + /** + * @description Updates `owner`'s allowance for `spender` based on spent `value`. + * Does not update the allowance value in case of infinite allowance. + * + * @param {owner} - The owner of the tokens. + * @param {spender} - The spender of the tokens. + * @param {value} - The amount of token allowance to spend. + * @return {[]} - None. + */ + export circuit _spendAllowance( + owner: Either, + spender: Either, + value: Uint<128> + ): [] { + // TODO: Look into improving design so we're not checking allowance member twice (here and in `_approve`) + assert (_allowances.member(owner) && _allowances.lookup(owner).member(spender)) "ERC20: insufficient allowance"; + + const currentAllowance = _allowances.lookup(owner).lookup(spender); + // TODO: improve readability of max_u128 + const MAX_UINT128 = 340282366920938463463374607431768211455; + if (currentAllowance < MAX_UINT128) { + assert currentAllowance >= value "ERC20: insufficient allowance"; + _approve(owner, spender, currentAllowance - value as Uint<128>); + } + } + + /** + * @description Returns whether `keyOrAddress` is the zero address. + * @todo Move to a utils contract since this will likely be reused. + * + * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. + * @return {Boolean} - Returns true if `keyOrAddress` is zero. + */ + //export pure circuit Utils_isKeyOrAddressZero(keyOrAddress: Either): Boolean { + // const zero = pad(32, ""); +// + // if (keyOrAddress.is_left) { + // return keyOrAddress == left(ZswapCoinPublicKey{ zero }); + // } else { + // return keyOrAddress == right(ContractAddress{ zero }); + // } + //} +} diff --git a/contracts/erc20/src/test/erc20.test.ts b/contracts/erc20/src/test/erc20.test.ts new file mode 100644 index 00000000..939f1c2b --- /dev/null +++ b/contracts/erc20/src/test/erc20.test.ts @@ -0,0 +1,471 @@ +import { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; +import { ERC20Simulator } from './simulators'; +import { MaybeString } from './types'; +import * as utils from './utils'; + +const NO_STRING: MaybeString = { + is_some: false, + value: '' +}; +const NAME: MaybeString = { + is_some: true, + value: "NAME" +}; +const SYMBOL: MaybeString = { + is_some: true, + value: "SYMBOL" +}; +const DECIMALS: bigint = 18n; + +const AMOUNT: bigint = BigInt(250); +const MAX_UINT128 = BigInt(2**128) - BigInt(1); + +const OWNER = String(Buffer.from("OWNER", 'ascii').toString('hex')).padStart(64, '0'); +const SPENDER = String(Buffer.from("SPENDER", 'ascii').toString('hex')).padStart(64, '0'); +const UNAUTHORIZED = String(Buffer.from("UNAUTHORIZED", 'ascii').toString('hex')).padStart(64, '0'); +const ZERO = String().padStart(64, '0'); +const Z_OWNER = utils.createEitherTestUser('OWNER'); +const Z_RECIPIENT = utils.createEitherTestUser('RECIPIENT'); +const Z_SPENDER = utils.createEitherTestUser('SPENDER'); +const Z_OTHER = utils.createEitherTestUser('OTHER'); +const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); + +let token: ERC20Simulator; +let caller: CoinPublicKey; + +describe('ERC20', () => { + describe('initializer and metadata', () => { + it('should initialize metadata', () => { + token = new ERC20Simulator(NAME, SYMBOL, DECIMALS); + + expect(token.name()).toEqual(NAME); + expect(token.symbol()).toEqual(SYMBOL); + expect(token.decimals()).toEqual(DECIMALS); + }); + + it('should initialize empty metadata', () => { + const NO_DECIMALS = 0n; + token = new ERC20Simulator(NO_STRING, NO_STRING, NO_DECIMALS); + + expect(token.name()).toEqual(NO_STRING); + expect(token.symbol()).toEqual(NO_STRING); + expect(token.decimals()).toEqual(NO_DECIMALS); + }); + }); + + beforeEach(() => { + token = new ERC20Simulator(NAME, SYMBOL, DECIMALS); + }); + + describe('totalSupply', () => { + it('returns 0 when there is no supply', () => { + expect(token.totalSupply()).toEqual(0n); + }); + + it('returns the amount of existing tokens when there is a supply', () => { + token._mint(Z_OWNER, AMOUNT); + expect(token.totalSupply()).toEqual(AMOUNT); + }) + }) + + describe('balanceOf', () => { + it('should return zero when requested account has no balance', () => { + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + + it('should return balance when requested account has tokens', () => { + token._mint(Z_OWNER, AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + }); + }); + + describe('transfer', () => { + beforeEach(() => { + token._mint(Z_OWNER, AMOUNT); + + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); + }); + + afterEach(() => { + expect(token.totalSupply()).toEqual(AMOUNT); + }); + + it('should transfer partial', () => { + const partialAmt = AMOUNT - 1n; + caller = OWNER; + const txSuccess = token.transfer(Z_RECIPIENT, partialAmt, caller); + + expect(txSuccess).toBeTruthy(); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); + }); + + it('should transfer full', () => { + caller = OWNER; + const txSuccess = token.transfer(Z_RECIPIENT, AMOUNT, caller); + + expect(txSuccess).toBeTruthy(); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); + }); + + it('should fail with insufficient balance', () => { + caller = OWNER; + + expect(() => { + token.transfer(Z_RECIPIENT, AMOUNT + 1n, caller); + }).toThrow('ERC20: insufficient balance'); + }); + + it('should fail with transfer from zero', () => { + caller = ZERO; + + expect(() => { + token.transfer(Z_RECIPIENT, AMOUNT, caller); + }).toThrow('ERC20: invalid sender'); + }); + + it('should fail with transfer to zero', () => { + caller = OWNER; + + expect(() => { + token.transfer(utils.ZERO_ADDRESS, AMOUNT, caller); + }).toThrow('ERC20: invalid receiver'); + }); + + it('should allow transfer of 0 tokens', () => { + const txSuccess = token.transfer(Z_RECIPIENT, 0n, caller); + + expect(txSuccess).toBeTruthy(); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); + }); + + it('should handle transfer with empty _balances', () => { + caller = SPENDER; + + expect(() => { + token.transfer(Z_RECIPIENT, 1n, caller); + }).toThrow('ERC20: insufficient balance'); + }); + }); + + describe('approve', () => { + beforeEach(() => { + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + + it('should approve and update allowance', () => { + caller = OWNER; + + token.approve(Z_SPENDER, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); + }); + + it('should approve and update allowance for multiple spenders', () => { + caller = OWNER; + + token.approve(Z_SPENDER, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); + + token.approve(Z_OTHER, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_OTHER)).toEqual(AMOUNT); + + expect(token.allowance(Z_OWNER, Z_RECIPIENT)).toEqual(0n); + }); + + it('should fail when approve from zero', () => { + caller = ZERO; + + expect(() => { + token.approve(Z_SPENDER, AMOUNT, caller); + }).toThrow('ERC20: invalid owner'); + }); + + it('should fail when approve to zero', () => { + caller = OWNER; + + expect(() => { + token.approve(utils.ZERO_ADDRESS, AMOUNT, caller); + }).toThrow('ERC20: invalid spender'); + }); + + it('should transfer exact allowance and fail subsequent transfer', () => { + token._mint(Z_OWNER, AMOUNT); + caller = OWNER; + token.approve(Z_SPENDER, AMOUNT, caller); + + caller = SPENDER; + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, 1n, caller); + }).toThrow('ERC20: insufficient allowance'); + }); + + it('should allow approve of 0 tokens', () => { + caller = OWNER; + token.approve(Z_SPENDER, 0n, caller); + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + + it('should handle allowance with empty _allowances', () => { + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + }); + + describe('transferFrom', () => { + beforeEach(() => { + caller = OWNER; + + token.approve(Z_SPENDER, AMOUNT, caller); + token._mint(Z_OWNER, AMOUNT); + }); + + afterEach(() => { + expect(token.totalSupply()).toEqual(AMOUNT); + }); + + it('should transferFrom spender (partial)', () => { + caller = SPENDER; + const partialAmt = AMOUNT - 1n; + + const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, partialAmt, caller); + expect(txSuccess).toBeTruthy(); + + // Check balances + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); + // Check leftover allowance + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(1n); + }); + + it('should transferFrom spender (full)', () => { + caller = SPENDER; + + const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + expect(txSuccess).toBeTruthy(); + + // Check balances + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); + // Check no allowance + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); + }); + + it('should transferFrom and not consume infinite allowance', () => { + caller = OWNER; + token.approve(Z_SPENDER, MAX_UINT128, caller); + + caller = SPENDER; + const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + expect(txSuccess).toBeTruthy(); + + // Check balances + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); + // Check infinite allowance + expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(MAX_UINT128); + }); + + it ('should fail when transfer amount exceeds allowance', () => { + caller = SPENDER; + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n); + }).toThrow('ERC20: insufficient allowance'); + }); + + it ('should fail when transfer amount exceeds balance', () => { + caller = OWNER; + // Increase allowance > balance + token.approve(Z_SPENDER, AMOUNT + 1n, caller); + + caller = SPENDER; + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n, caller); + }).toThrow('ERC20: insufficient balance'); + }); + + it('should fail when spender does not have allowance', () => { + caller = UNAUTHORIZED; + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + }).toThrow("ERC20: insufficient allowance"); + }); + + it('should fail to transferFrom zero address', () => { + caller = ZERO; + + expect(() => { + token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + }).toThrow("ERC20: insufficient allowance"); + }); + + it('should fail to transferFrom to the zero address', () => { + caller = SPENDER; + + expect(() => { + token.transferFrom(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT, caller); + }).toThrow("ERC20: invalid receiver"); + }); + }); + + describe('_transfer', () => { + beforeEach(() => { + token._mint(Z_OWNER, AMOUNT); + }); + + afterEach(() => { + expect(token.totalSupply()).toEqual(AMOUNT); + }); + + it('should update balances (partial)', () => { + const partialAmt = AMOUNT - 1n; + token._transfer(Z_OWNER, Z_RECIPIENT, partialAmt); + + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); + }); + }) + + describe('_mint', () => { + it('should mint and update supply', () => { + expect(token.totalSupply()).toEqual(0n); + + token._mint(Z_RECIPIENT, AMOUNT); + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); + }); + + it('should catch mint overflow', () => { + token._mint(Z_RECIPIENT, MAX_UINT128); + + expect(() => { + token._mint(Z_RECIPIENT, 1n); + }).toThrow('ERC20: arithmetic overflow'); + }); + + it('should not mint to zero pubkey', () => { + expect(() => { + token._mint(utils.ZERO_KEY, AMOUNT); + }).toThrow('ERC20: invalid receiver'); + }); + + it('should not mint to zero contract address', () => { + expect(() => { + token._mint(utils.ZERO_ADDRESS, AMOUNT); + }).toThrow('ERC20: invalid receiver'); + }); + + it('should allow mint of 0 tokens', () => { + token._mint(Z_OWNER, 0n); + expect(token.totalSupply()).toEqual(0n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + }); + + describe('_burn', () => { + beforeEach(() => { + token._mint(Z_OWNER, AMOUNT); + }); + + it('should burn tokens', () => { + token._burn(Z_OWNER, 1n); + + const afterBurn = AMOUNT - 1n; + expect(token.balanceOf(Z_OWNER)).toEqual(afterBurn); + expect(token.totalSupply()).toEqual(afterBurn); + }); + + it('should throw when burning from zero', () => { + expect(() => { + token._burn(utils.ZERO_KEY, AMOUNT); + }).toThrow('ERC20: invalid sender'); + }); + + it('should throw when burn amount is greater than balance', () => { + expect(() => { + token._burn(Z_OWNER, AMOUNT + 1n); + }).toThrow('ERC20: insufficient balance'); + }); + + it('should allow burn of 0 tokens', () => { + token._burn(Z_OWNER, 0n); + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + }); + }); + + describe('_update', () => { + it('should update from zero to non-zero (mint)', () => { + expect(token.totalSupply()).toEqual(0n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + + token._update(utils.ZERO_KEY, Z_OWNER, AMOUNT); + + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + }); + + it('should catch overflow from zero to non-zero (mint)', () => { + token._update(utils.ZERO_KEY, Z_OWNER, MAX_UINT128); + + expect(() => { + token._update(utils.ZERO_KEY, Z_OWNER, 1n); + }).toThrow('ERC20: arithmetic overflow'); + }); + + describe('with minted tokens', () => { + beforeEach(() => { + token._update(utils.ZERO_ADDRESS, Z_OWNER, AMOUNT); + + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + }); + + it('should update from non-zero to zero (burn)', () => { + token._update(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); + + expect(token.totalSupply()).toEqual(0n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + + it('should catch overflow from non-zero to zero (burn)', () => { + token._update(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); + + expect(() => { + token._update(Z_OWNER, utils.ZERO_ADDRESS, 1n); + }).toThrow('ERC20: insufficient balance'); + }); + + it('should update from non-zero to non-zero (transfer)', () => { + token._update(Z_OWNER, Z_RECIPIENT, AMOUNT - 1n); + + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); + }); + }); + }); + + describe('Multiple Operations', () => { + it('should handle mint → transfer → burn sequence', () => { + token._mint(Z_OWNER, AMOUNT); + expect(token.totalSupply()).toEqual(AMOUNT); + expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); + + caller = OWNER; + token.transfer(Z_RECIPIENT, AMOUNT - 1n, caller); + expect(token.balanceOf(Z_OWNER)).toEqual(1n); + expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); + + token._burn(Z_OWNER, 1n); + expect(token.totalSupply()).toEqual(AMOUNT - 1n); + expect(token.balanceOf(Z_OWNER)).toEqual(0n); + }); + }); +}); diff --git a/contracts/erc20/src/test/mocks/MockERC20.compact b/contracts/erc20/src/test/mocks/MockERC20.compact new file mode 100644 index 00000000..e5e8a9da --- /dev/null +++ b/contracts/erc20/src/test/mocks/MockERC20.compact @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.14.0; + +import CompactStandardLibrary; + +import "../../ERC20" prefix ERC20_; + +export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; + +constructor( + _name: Maybe>, + _symbol: Maybe>, + _decimals:Uint<8> +) { + ERC20_initializer(_name, _symbol, _decimals); +} + +export circuit name(): Maybe> { + return ERC20_name(); +} + +export circuit symbol(): Maybe> { + return ERC20_symbol(); +} + +export circuit decimals(): Uint<8> { + return ERC20_decimals(); +} + +export circuit totalSupply(): Uint<128> { + return ERC20_totalSupply(); +} + +export circuit balanceOf(account: Either): Uint<128> { + return ERC20_balanceOf(account); +} + +export circuit allowance( + owner: Either, + spender: Either +): Uint<128> { + return ERC20_allowance(owner, spender); +} + +export circuit transfer(to: Either, value: Uint<128>): Boolean { + return ERC20_transfer(to, value); +} + +export circuit transferFrom( + from: Either, + to: Either, + value: Uint<128> +): Boolean { + return ERC20_transferFrom(from, to, value); +} + +export circuit approve(spender: Either, value: Uint<128>): Boolean { + return ERC20_approve(spender, value); +} + +export circuit _approve( + owner: Either, + spender: Either, + value: Uint<128> +): [] { + return ERC20__approve(owner, spender, value); +} + +export circuit _transfer( + from: Either, + to: Either, + value: Uint<128> +): [] { + return ERC20__transfer(from, to, value); +} + +export circuit _mint( + account: Either, + value: Uint<128> +): [] { + return ERC20__mint(account, value); +} + +export circuit _burn( + account: Either, + value: Uint<128> +): [] { + return ERC20__burn(account, value); +} + +export circuit _update( + from: Either, + to: Either, + value: Uint<128> +): [] { + return ERC20__update(from, to, value); +} + +export circuit _spendAllowance( + owner: Either, + spender: Either, + value: Uint<128> +): [] { + return ERC20__spendAllowance(owner, spender, value); +} diff --git a/contracts/erc20/src/test/simulators/ERC20Simulator.ts b/contracts/erc20/src/test/simulators/ERC20Simulator.ts new file mode 100644 index 00000000..a8e324da --- /dev/null +++ b/contracts/erc20/src/test/simulators/ERC20Simulator.ts @@ -0,0 +1,299 @@ +import { + type CircuitContext, + CoinPublicKey, + type ContractState, + QueryContext, + constructorContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import { sampleContractAddress } from '@midnight-ntwrk/zswap'; +import { + type Ledger, + Contract as MockERC20, + ledger, + Either, + ZswapCoinPublicKey, + ContractAddress, +} from '../../artifacts/MockERC20/contract/index.cjs'; // Combined imports +import { MaybeString } from '../types'; +import type { IContractSimulator } from './../types'; +import { ERC20PrivateState, ERC20Witnesses } from '../../witnesses'; + +/** + * @description A simulator implementation of an erc20 contract for testing purposes. + * @template P - The private state type, fixed to ERC20PrivateState. + * @template L - The ledger type, fixed to Contract.Ledger. + */ +export class ERC20Simulator + implements IContractSimulator +{ + /** @description The underlying contract instance managing contract logic. */ + readonly contract: MockERC20; + + /** @description The deployed address of the contract. */ + readonly contractAddress: string; + + /** @description The current circuit context, updated by contract operations. */ + circuitContext: CircuitContext; + + /** + * @description Initializes the mock contract. + */ + constructor(name: MaybeString, symbol: MaybeString, decimals: bigint) { + this.contract = new MockERC20( + ERC20Witnesses, + ); + const { + currentPrivateState, + currentContractState, + currentZswapLocalState, + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)), name, symbol, decimals, + ); + this.circuitContext = { + currentPrivateState, + currentZswapLocalState, + originalState: currentContractState, + transactionContext: new QueryContext( + currentContractState.data, + sampleContractAddress(), + ), + }; + this.contractAddress = this.circuitContext.transactionContext.address; + } + + /** + * @description Retrieves the current public ledger state of the contract. + * @returns The ledger state as defined by the contract. + */ + public getCurrentPublicState(): Ledger { + return ledger(this.circuitContext.transactionContext.state); + } + + /** + * @description Retrieves the current private state of the contract. + * @returns The private state of type ERC20PrivateState. + */ + public getCurrentPrivateState(): ERC20PrivateState { + return this.circuitContext.currentPrivateState; + } + + /** + * @description Retrieves the current contract state. + * @returns The contract state object. + */ + public getCurrentContractState(): ContractState { + return this.circuitContext.originalState; + } + + /** + * @description Returns the token name. + * @returns The token name. + */ + public name(): MaybeString { + return this.contract.impureCircuits.name(this.circuitContext).result; + } + + /** + * @description Returns the symbol of the token. + * @returns The token name. + */ + public symbol(): MaybeString { + return this.contract.impureCircuits.symbol(this.circuitContext).result; + } + + /** + * @description Returns the number of decimals used to get its user representation. + * @returns The account's token balance. + */ + public decimals(): bigint { + return this.contract.impureCircuits.decimals(this.circuitContext).result; + } + + /** + * @description Returns the value of tokens in existence. + * @returns The total supply of tokens. + */ + public totalSupply(): bigint { + return this.contract.impureCircuits.totalSupply(this.circuitContext).result; + } + + /** + * @description Returns the value of tokens owned by `account`. + * @param account The public key or contract address to query. + * @returns The account's token balance. + */ + public balanceOf(account: Either): bigint { + return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; + } + + /** + * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` + * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. + * @param owner The public key or contract address of approver. + * @param spender The public key or contract address of spender. + * @returns The `spender`'s allowance over `owner`'s tokens. + */ + public allowance( + owner: Either, + spender: Either + ): bigint { + return this.contract.impureCircuits.allowance(this.circuitContext, owner, spender).result; + } + + /** + * @description Moves a `value` amount of tokens from the caller's account to `to`. + * @param to The recipient of the transfer, either a user or a contract. + * @param value The amount to transfer. + * @param sender The simulated caller. + * @returns As per the IERC20 spec, this MUST return true. + */ + public transfer(to: Either, value: bigint, sender?: CoinPublicKey): boolean { + const res = this.contract.impureCircuits.transfer({ + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, to, value + ); + + this.circuitContext = res.context; + return res.result; + } + + /** + * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. + * `value` is the deducted from the caller's allowance. + * @param from The current owner of the tokens for the transfer, either a user or a contract. + * @param to The recipient of the transfer, either a user or a contract. + * @param value The amount to transfer. + * @param sender The simulated caller. + * @returns As per the IERC20 spec, this MUST return true. + */ + public transferFrom( + from: Either, + to: Either, + value: bigint, + sender?: CoinPublicKey + ): boolean { + const res = this.contract.impureCircuits.transferFrom({ + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + from, to, value + ); + + this.circuitContext = res.context; + return res.result; + } + + /** + * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. + * @param spender The Zswap key or ContractAddress that may spend on behalf of the caller. + * @param value The amount of tokens the `spender` may spend. + * @param sender The simulated caller. + * @returns Returns a boolean value indicating whether the operation succeeded. + */ + public approve(spender: Either, value: bigint, sender?: CoinPublicKey): boolean { + const res = this.contract.impureCircuits.approve({ + ...this.circuitContext, + currentZswapLocalState: sender + ? emptyZswapLocalState(sender) + : this.circuitContext.currentZswapLocalState, + }, + spender, value + ); + + this.circuitContext = res.context; + return res.result; + } + + /// + /// Internal + /// + + /** + * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * @param owner The owner of the tokens. + * @param spender The spender of the tokens. + * @param value The amount of tokens `spender` may spend on behalf of `owner`. + * @returns None. + */ + public _approve( + owner: Either, + spender: Either, + value: bigint + ) { + this.circuitContext = this.contract.impureCircuits._approve(this.circuitContext, owner, spender, value).context; + } + + /** + * @description Moves a `value` amount of tokens from `from` to `to`. + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * @param from The owner of the tokens to transfer. + * @param to The receipient of the transferred tokens. + * @param value The amount of tokens to transfer. + */ + public _transfer( + from: Either, + to: Either, + value: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._transfer(this.circuitContext, from, to, value).context; + } + + /** + * @description Creates a `value` amount of tokens and assigns them to `account`, + * by transferring it from the zero address. Relies on the `update` mechanism. + * @param account The recipient of tokens minted. + * @param value The amount of tokens minted. + */ + public _mint(account: Either, value: bigint) { + this.circuitContext = this.contract.impureCircuits._mint(this.circuitContext, account, value).context; + } + + /** + * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. + * Relies on the `_update` mechanism. + * @param account The target owner of tokens to burn. + * @param value The amount of tokens to burn. + */ + public _burn(account: Either, value: bigint) { + this.circuitContext = this.contract.impureCircuits._burn(this.circuitContext, account, value).context; + } + + /** + * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` + * (or `to`) is the zero address. + * @param from The original owner of the tokens moved (which is 0 if tokens are minted). + * @param to The recipient of the tokens moved (which is 0 if tokens are burned). + * @param value The amount of tokens moved from `from` to `to`. + */ + public _update( + from: Either, + to: Either, + value: bigint + ) { + this.circuitContext = this.contract.impureCircuits._update(this.circuitContext, from, to, value).context; + } + + /** + * @description Updates `owner`'s allowance for `spender` based on spent `value`. + * Does not update the allowance value in case of infinite allowance. + * @param owner The owner of the tokens. + * @param spender The spender of the tokens. + * @param value The amount of token allowance to spend. + */ + public _spendAllowance( + owner: Either, + spender: Either, + value: bigint + ) { + this.circuitContext = this.contract.impureCircuits._spendAllowance(this.circuitContext, owner, spender, value).context; + } +} diff --git a/contracts/erc20/src/test/simulators/index.ts b/contracts/erc20/src/test/simulators/index.ts new file mode 100644 index 00000000..134f9c95 --- /dev/null +++ b/contracts/erc20/src/test/simulators/index.ts @@ -0,0 +1 @@ +export { ERC20Simulator } from './ERC20Simulator'; diff --git a/contracts/utils/contract/src/test/types/test.ts b/contracts/erc20/src/test/types/test.ts similarity index 100% rename from contracts/utils/contract/src/test/types/test.ts rename to contracts/erc20/src/test/types/test.ts diff --git a/contracts/erc20/src/test/utils/address.ts b/contracts/erc20/src/test/utils/address.ts new file mode 100644 index 00000000..ef9a2842 --- /dev/null +++ b/contracts/erc20/src/test/utils/address.ts @@ -0,0 +1,78 @@ +import { encodeContractAddress } from '@midnight-ntwrk/ledger'; +import * as Compact from '../../artifacts/MockERC20/contract/index.cjs'; +import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; + +const PREFIX_ADDRESS = "0200"; + +export const pad = (s: string, n: number): Uint8Array => { + const encoder = new TextEncoder(); + const utf8Bytes = encoder.encode(s); + if (n < utf8Bytes.length) { + throw new Error(`The padded length n must be at least ${utf8Bytes.length}`); + } + const paddedArray = new Uint8Array(n); + paddedArray.set(utf8Bytes); + return paddedArray; +} + +/** + * @description Generates ZswapCoinPublicKey from `str` for testing purposes. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { + const toHex = Buffer.from(str, 'ascii').toString('hex'); + return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; +} + +/** + * @description Generates ContractAddress from `str` for testing purposes. + * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. + * @param str String to hexify and encode. + * @returns Encoded `ZswapCoinPublicKey`. + */ +export const encodeToAddress = (str: string): Compact.ContractAddress => { + const toHex = Buffer.from(str, 'ascii').toString('hex'); + const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); + return { bytes: encodeContractAddress(fullAddress) }; +} + +/** + * @description Generates an Either object for ZswapCoinPublicKey for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ZswapCoinPublicKey. + */ +export const createEitherTestUser = (str: string) => { + return { + is_left: true, + left: encodeToPK(str), + right: encodeToAddress('') + } +} + +/** + * @description Generates an Either object for ContractAddress for testing. + * For use when an Either argument is expected. + * @param str String to hexify and encode. + * @returns Defined Either object for ContractAddress. + */ +export const createEitherTestContractAddress = (str: string) => { + return { + is_left: false, + left: encodeToPK(''), + right: encodeToAddress(str) + } +} + +export const ZERO_KEY = { + is_left: true, + left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, + right: encodeToAddress('') +} + +export const ZERO_ADDRESS = { + is_left: false, + left: encodeToPK(''), + right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) } +} diff --git a/contracts/erc20/src/test/utils/index.ts b/contracts/erc20/src/test/utils/index.ts new file mode 100644 index 00000000..731fe1ec --- /dev/null +++ b/contracts/erc20/src/test/utils/index.ts @@ -0,0 +1,2 @@ +export { useCircuitContext as circuitContext } from './test'; +export * from './address'; diff --git a/contracts/utils/contract/src/test/utils/test.ts b/contracts/erc20/src/test/utils/test.ts similarity index 100% rename from contracts/utils/contract/src/test/utils/test.ts rename to contracts/erc20/src/test/utils/test.ts diff --git a/contracts/erc20/src/witnesses/ERC20Witnesses.ts b/contracts/erc20/src/witnesses/ERC20Witnesses.ts new file mode 100644 index 00000000..ed372fb7 --- /dev/null +++ b/contracts/erc20/src/witnesses/ERC20Witnesses.ts @@ -0,0 +1,3 @@ +// This is how we type an empty object. +export type ERC20PrivateState = Record; +export const ERC20Witnesses = {}; diff --git a/contracts/erc20/src/witnesses/index.ts b/contracts/erc20/src/witnesses/index.ts new file mode 100644 index 00000000..dc29bf8e --- /dev/null +++ b/contracts/erc20/src/witnesses/index.ts @@ -0,0 +1,2 @@ +export * from '../artifacts/erc20/contract/index.cjs'; +export * from './ERC20Witnesses.js'; diff --git a/contracts/utils/contract/tsconfig.build.json b/contracts/erc20/tsconfig.build.json similarity index 100% rename from contracts/utils/contract/tsconfig.build.json rename to contracts/erc20/tsconfig.build.json diff --git a/contracts/erc20/tsconfig.json b/contracts/erc20/tsconfig.json new file mode 100644 index 00000000..3e90b0a9 --- /dev/null +++ b/contracts/erc20/tsconfig.json @@ -0,0 +1,21 @@ +{ + "include": ["src/**/*.ts"], + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "lib": ["ESNext"], + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "node", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": true, + "strict": true, + "isolatedModules": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true + } +} diff --git a/contracts/initializable/src/Initializable.compact b/contracts/initializable/src/Initializable.compact new file mode 100644 index 00000000..648f7670 --- /dev/null +++ b/contracts/initializable/src/Initializable.compact @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma language_version >= 0.14.0; + +/** + * @module Initializable + * @description Initializable provides a simple mechanism that mimics the functionality of a constructor. + */ +module Initializable{ + import CompactStandardLibrary; + + export enum STATE { uninitialized, initialized } + + export ledger state: STATE; + + /** + * @description Initializes the state thus ensuring the calling circuit can only be called once. + * + * @returns None. + */ + export circuit initialize(): [] { + assert state == STATE.uninitialized "Contract already initialized"; + state = STATE.initialized; + } + + /** + * @description Returns true if the state is initialized. + * + * @returns {Boolean} - whether the contract has been initialized. + */ + export circuit isInitialized(): Boolean { + return (state == STATE.initialized); + } +} diff --git a/contracts/utils/contract/src/witnesses/MockInitializable.compact b/contracts/initializable/src/MockInitializable.compact similarity index 100% rename from contracts/utils/contract/src/witnesses/MockInitializable.compact rename to contracts/initializable/src/MockInitializable.compact diff --git a/contracts/initializable/contract/src/test/InitializableSimulator.ts b/contracts/initializable/src/test/InitializableSimulator.ts similarity index 100% rename from contracts/initializable/contract/src/test/InitializableSimulator.ts rename to contracts/initializable/src/test/InitializableSimulator.ts diff --git a/contracts/initializable/src/test/initializable.test.ts b/contracts/initializable/src/test/initializable.test.ts new file mode 100644 index 00000000..15ee059c --- /dev/null +++ b/contracts/initializable/src/test/initializable.test.ts @@ -0,0 +1,32 @@ +import { it, describe, expect } from '@jest/globals'; +import { InitializableSimulator } from './InitializableSimulator.js'; +import { Initializable_STATE as STATE } from '../artifacts/MockInitializable/contract/index.cjs'; + +const contract = new InitializableSimulator(); + +describe('Initializable', () => { + it('should generate the initial ledger state deterministically', () => { + const contract2 = new InitializableSimulator(); + expect(contract.getCurrentPublicState()).toEqual(contract2.getCurrentPublicState()); + }); + + describe('initialize', () => { + it('should not be initialized', () => { + expect(contract.isInitialized()).toEqual(false); + expect(contract.getCurrentPublicState().initializableState).toEqual(STATE.uninitialized); + }); + + it('should initialize', () => { + contract.initialize(); + expect(contract.isInitialized()).toEqual(true); + expect(contract.getCurrentPublicState().initializableState).toEqual(STATE.initialized); + }); + }); + + it('should fail when re-initialized', () => { + expect(() => { + contract.initialize(); + contract.initialize(); + }).toThrow('Contract already initialized'); + }); +}); diff --git a/contracts/initializable/contract/src/test/types/index.ts b/contracts/initializable/src/test/types/index.ts similarity index 100% rename from contracts/initializable/contract/src/test/types/index.ts rename to contracts/initializable/src/test/types/index.ts diff --git a/contracts/initializable/contract/src/test/types/test.ts b/contracts/initializable/src/test/types/test.ts similarity index 100% rename from contracts/initializable/contract/src/test/types/test.ts rename to contracts/initializable/src/test/types/test.ts diff --git a/contracts/initializable/contract/src/test/utils/index.ts b/contracts/initializable/src/test/utils/index.ts similarity index 100% rename from contracts/initializable/contract/src/test/utils/index.ts rename to contracts/initializable/src/test/utils/index.ts diff --git a/contracts/initializable/contract/src/test/utils/test.ts b/contracts/initializable/src/test/utils/test.ts similarity index 100% rename from contracts/initializable/contract/src/test/utils/test.ts rename to contracts/initializable/src/test/utils/test.ts diff --git a/contracts/initializable/contract/src/witnesses/InitializableWitnesses.ts b/contracts/initializable/src/witnesses/InitializableWitnesses.ts similarity index 100% rename from contracts/initializable/contract/src/witnesses/InitializableWitnesses.ts rename to contracts/initializable/src/witnesses/InitializableWitnesses.ts diff --git a/contracts/initializable/contract/src/witnesses/index.ts b/contracts/initializable/src/witnesses/index.ts similarity index 100% rename from contracts/initializable/contract/src/witnesses/index.ts rename to contracts/initializable/src/witnesses/index.ts diff --git a/contracts/initializable/tsconfig.build.json b/contracts/initializable/tsconfig.build.json new file mode 100644 index 00000000..f1132509 --- /dev/null +++ b/contracts/initializable/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["src/test/**/*.ts"], + "compilerOptions": {} +} diff --git a/contracts/initializable/tsconfig.json b/contracts/initializable/tsconfig.json new file mode 100644 index 00000000..d6c626dc --- /dev/null +++ b/contracts/initializable/tsconfig.json @@ -0,0 +1,21 @@ +{ + "include": ["src/**/*.ts"], + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "lib": ["ES2022"], + "target": "ES2022", + "module": "nodenext", + "moduleResolution": "nodenext", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": true, + "strict": true, + "isolatedModules": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true + } +} \ No newline at end of file diff --git a/contracts/utils/contract/package.json b/contracts/utils/package.json similarity index 100% rename from contracts/utils/contract/package.json rename to contracts/utils/package.json diff --git a/contracts/utils/contract/src/Initializable.compact b/contracts/utils/src/Initializable.compact similarity index 100% rename from contracts/utils/contract/src/Initializable.compact rename to contracts/utils/src/Initializable.compact diff --git a/contracts/utils/contract/src/MockUtils.compact b/contracts/utils/src/MockUtils.compact similarity index 100% rename from contracts/utils/contract/src/MockUtils.compact rename to contracts/utils/src/MockUtils.compact diff --git a/contracts/utils/contract/src/Pausable.compact b/contracts/utils/src/Pausable.compact similarity index 100% rename from contracts/utils/contract/src/Pausable.compact rename to contracts/utils/src/Pausable.compact diff --git a/contracts/utils/contract/src/Utils.compact b/contracts/utils/src/Utils.compact similarity index 100% rename from contracts/utils/contract/src/Utils.compact rename to contracts/utils/src/Utils.compact diff --git a/contracts/utils/contract/src/test/Initializable.test.ts b/contracts/utils/src/test/Initializable.test.ts similarity index 100% rename from contracts/utils/contract/src/test/Initializable.test.ts rename to contracts/utils/src/test/Initializable.test.ts diff --git a/contracts/utils/contract/src/test/Pausable.test.ts b/contracts/utils/src/test/Pausable.test.ts similarity index 100% rename from contracts/utils/contract/src/test/Pausable.test.ts rename to contracts/utils/src/test/Pausable.test.ts diff --git a/contracts/utils/contract/src/test/UtilsSimulator.ts b/contracts/utils/src/test/UtilsSimulator.ts similarity index 100% rename from contracts/utils/contract/src/test/UtilsSimulator.ts rename to contracts/utils/src/test/UtilsSimulator.ts diff --git a/contracts/utils/contract/src/test/mocks/MockInitializable.compact b/contracts/utils/src/test/mocks/MockInitializable.compact similarity index 100% rename from contracts/utils/contract/src/test/mocks/MockInitializable.compact rename to contracts/utils/src/test/mocks/MockInitializable.compact diff --git a/contracts/utils/contract/src/test/mocks/MockPausable.compact b/contracts/utils/src/test/mocks/MockPausable.compact similarity index 100% rename from contracts/utils/contract/src/test/mocks/MockPausable.compact rename to contracts/utils/src/test/mocks/MockPausable.compact diff --git a/contracts/utils/contract/src/test/mocks/MockUtils.compact b/contracts/utils/src/test/mocks/MockUtils.compact similarity index 100% rename from contracts/utils/contract/src/test/mocks/MockUtils.compact rename to contracts/utils/src/test/mocks/MockUtils.compact diff --git a/contracts/utils/contract/src/test/simulators/InitializableSimulator.ts b/contracts/utils/src/test/simulators/InitializableSimulator.ts similarity index 100% rename from contracts/utils/contract/src/test/simulators/InitializableSimulator.ts rename to contracts/utils/src/test/simulators/InitializableSimulator.ts diff --git a/contracts/utils/contract/src/test/simulators/PausableSimulator.ts b/contracts/utils/src/test/simulators/PausableSimulator.ts similarity index 100% rename from contracts/utils/contract/src/test/simulators/PausableSimulator.ts rename to contracts/utils/src/test/simulators/PausableSimulator.ts diff --git a/contracts/utils/contract/src/test/simulators/UtilsSimulator.ts b/contracts/utils/src/test/simulators/UtilsSimulator.ts similarity index 100% rename from contracts/utils/contract/src/test/simulators/UtilsSimulator.ts rename to contracts/utils/src/test/simulators/UtilsSimulator.ts diff --git a/contracts/utils/src/test/types/index.ts b/contracts/utils/src/test/types/index.ts new file mode 100644 index 00000000..db642b5e --- /dev/null +++ b/contracts/utils/src/test/types/index.ts @@ -0,0 +1 @@ +export type { IContractSimulator } from './test'; diff --git a/contracts/utils/src/test/types/test.ts b/contracts/utils/src/test/types/test.ts new file mode 100644 index 00000000..10fb6c98 --- /dev/null +++ b/contracts/utils/src/test/types/test.ts @@ -0,0 +1,23 @@ +import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; + +/** + * Generic interface for mock contract implementations. + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + */ +export interface IContractSimulator { + /** The contract's deployed address. */ + readonly contractAddress: string; + + /** The current circuit context. */ + circuitContext: CircuitContext

; + + /** Retrieves the current ledger state. */ + getCurrentPublicState(): L; + + /** Retrieves the current private state. */ + getCurrentPrivateState(): P; + + /** Retrieves the current contract state. */ + getCurrentContractState(): ContractState; +} diff --git a/contracts/utils/contract/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts similarity index 100% rename from contracts/utils/contract/src/test/utils.test.ts rename to contracts/utils/src/test/utils.test.ts diff --git a/contracts/utils/contract/src/test/utils/address.ts b/contracts/utils/src/test/utils/address.ts similarity index 100% rename from contracts/utils/contract/src/test/utils/address.ts rename to contracts/utils/src/test/utils/address.ts diff --git a/contracts/utils/contract/src/test/utils/index.ts b/contracts/utils/src/test/utils/index.ts similarity index 100% rename from contracts/utils/contract/src/test/utils/index.ts rename to contracts/utils/src/test/utils/index.ts diff --git a/contracts/utils/src/test/utils/test.ts b/contracts/utils/src/test/utils/test.ts new file mode 100644 index 00000000..940ed612 --- /dev/null +++ b/contracts/utils/src/test/utils/test.ts @@ -0,0 +1,67 @@ +import { + type CircuitContext, + type CoinPublicKey, + type ContractAddress, + type ContractState, + QueryContext, + emptyZswapLocalState, +} from '@midnight-ntwrk/compact-runtime'; +import type { IContractSimulator } from '../types'; + +/** + * Constructs a `CircuitContext` from the given state and sender information. + * + * This is typically used at runtime to provide the necessary context + * for executing circuits, including contract state, private state, + * sender identity, and transaction data. + * + * @template P - The type of the contract's private state. + * @param privateState - The current private state of the contract. + * @param contractState - The full contract state, including public and private data. + * @param sender - The public key of the sender (used in the circuit). + * @param contractAddress - The address of the deployed contract. + * @returns A fully populated `CircuitContext` for circuit execution. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContext

( + privateState: P, + contractState: ContractState, + sender: CoinPublicKey, + contractAddress: ContractAddress, +): CircuitContext

{ + return { + originalState: contractState, + currentPrivateState: privateState, + transactionContext: new QueryContext(contractState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} + +/** + * Prepares a new `CircuitContext` using the given sender and contract. + * + * Useful for mocking or updating the circuit context with a custom sender. + * + * @template P - The type of the contract's private state. + * @template L - The type of the contract's ledger (public state). + * @template C - The specific type of the contract implementing `MockContract`. + * @param contract - The contract instance implementing `MockContract`. + * @param sender - The public key to set as the sender in the new circuit context. + * @returns A new `CircuitContext` with the sender and updated context values. + * @todo TODO: Move this utility to a generic package for broader reuse across contracts. + */ +export function useCircuitContextSender>( + contract: C, + sender: CoinPublicKey, +): CircuitContext

{ + const currentPrivateState = contract.getCurrentPrivateState(); + const originalState = contract.getCurrentContractState(); + const contractAddress = contract.contractAddress; + + return { + originalState, + currentPrivateState, + transactionContext: new QueryContext(originalState.data, contractAddress), + currentZswapLocalState: emptyZswapLocalState(sender), + }; +} diff --git a/contracts/utils/contract/src/witnesses/InitializableWitnesses.ts b/contracts/utils/src/witnesses/InitializableWitnesses.ts similarity index 100% rename from contracts/utils/contract/src/witnesses/InitializableWitnesses.ts rename to contracts/utils/src/witnesses/InitializableWitnesses.ts diff --git a/contracts/utils/src/witnesses/MockInitializable.compact b/contracts/utils/src/witnesses/MockInitializable.compact new file mode 100644 index 00000000..d670f6d9 --- /dev/null +++ b/contracts/utils/src/witnesses/MockInitializable.compact @@ -0,0 +1,14 @@ +pragma language_version >= 0.14.0; + +import CompactStandardLibrary; +import Initializable prefix Initializable_; + +export { Initializable_state, Initializable_STATE }; + +export circuit initialize(): [] { + return Initializable_initialize(); +} + +export circuit isInitialized(): Boolean { + return Initializable_isInitialized(); +} diff --git a/contracts/utils/contract/src/witnesses/PausableWitnesses.ts b/contracts/utils/src/witnesses/PausableWitnesses.ts similarity index 100% rename from contracts/utils/contract/src/witnesses/PausableWitnesses.ts rename to contracts/utils/src/witnesses/PausableWitnesses.ts diff --git a/contracts/utils/contract/src/witnesses/UtilsWitnesses.ts b/contracts/utils/src/witnesses/UtilsWitnesses.ts similarity index 100% rename from contracts/utils/contract/src/witnesses/UtilsWitnesses.ts rename to contracts/utils/src/witnesses/UtilsWitnesses.ts diff --git a/contracts/utils/contract/src/witnesses/index.ts b/contracts/utils/src/witnesses/index.ts similarity index 100% rename from contracts/utils/contract/src/witnesses/index.ts rename to contracts/utils/src/witnesses/index.ts diff --git a/contracts/utils/tsconfig.build.json b/contracts/utils/tsconfig.build.json new file mode 100644 index 00000000..f1132509 --- /dev/null +++ b/contracts/utils/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["src/test/**/*.ts"], + "compilerOptions": {} +} diff --git a/contracts/utils/contract/tsconfig.json b/contracts/utils/tsconfig.json similarity index 100% rename from contracts/utils/contract/tsconfig.json rename to contracts/utils/tsconfig.json From 76cf6bdf93e2cf7d83d2b25c6bdf24529a5a96df Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 11 Apr 2025 09:58:09 -0500 Subject: [PATCH 267/282] tidy up code (#23) --- contracts/erc20/src/ERC20.compact | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/contracts/erc20/src/ERC20.compact b/contracts/erc20/src/ERC20.compact index 0f520112..96bdab69 100644 --- a/contracts/erc20/src/ERC20.compact +++ b/contracts/erc20/src/ERC20.compact @@ -325,21 +325,4 @@ module ERC20 { _approve(owner, spender, currentAllowance - value as Uint<128>); } } - - /** - * @description Returns whether `keyOrAddress` is the zero address. - * @todo Move to a utils contract since this will likely be reused. - * - * @param {keyOrAddress} - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. - * @return {Boolean} - Returns true if `keyOrAddress` is zero. - */ - //export pure circuit Utils_isKeyOrAddressZero(keyOrAddress: Either): Boolean { - // const zero = pad(32, ""); -// - // if (keyOrAddress.is_left) { - // return keyOrAddress == left(ZswapCoinPublicKey{ zero }); - // } else { - // return keyOrAddress == right(ContractAddress{ zero }); - // } - //} } From 5450cde08bce85c0c187861f095418bbcd69523a Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Sat, 26 Apr 2025 00:53:30 -0500 Subject: [PATCH 268/282] Add pausable (#22) * add pausable * update repo structure * move mock contracts to mocks dir * fix initializable tests * move mocks to test * add comments to pausable simulator * add return type to isPaused * add line * fix comment * simplify build script * improve simulator export * fix test file name * Rename pausable.test.ts to Pausable.test.ts * chore: initializable in pausable style (#34) * move initializable and pausable to utils/ * remove barrel files, fix tests * update initializable mock, sim, and tests --------- Co-authored-by: Iskander --- contracts/erc20/src/test/erc20.test.ts | 16 ++-- .../src/test/simulators/ERC20Simulator.ts | 6 +- contracts/erc20/src/test/simulators/index.ts | 1 - contracts/erc20/src/test/utils/test.ts | 4 + contracts/erc20/src/witnesses/index.ts | 2 - .../initializable/src/Initializable.compact | 33 ------- .../src/MockInitializable.compact | 14 --- .../src/test/InitializableSimulator.ts | 88 ----------------- .../src/test/initializable.test.ts | 32 ------- .../initializable/src/test/types/index.ts | 1 - .../initializable/src/test/types/test.ts | 23 ----- .../initializable/src/test/utils/index.ts | 1 - .../initializable/src/test/utils/test.ts | 67 ------------- .../src/witnesses/InitializableWitnesses.ts | 3 - .../initializable/src/witnesses/index.ts | 2 - contracts/initializable/tsconfig.build.json | 5 - contracts/initializable/tsconfig.json | 21 ----- contracts/utils/package.json | 9 ++ contracts/utils/src/Initializable.compact | 4 + contracts/utils/src/MockUtils.compact | 13 --- contracts/utils/src/Pausable.compact | 4 + .../utils/src/test/Initializable.test.ts | 25 +++++ contracts/utils/src/test/Pausable.test.ts | 9 ++ contracts/utils/src/test/UtilsSimulator.ts | 94 ------------------- .../src/test/mocks/MockInitializable.compact | 4 + .../utils/src/test/mocks/MockPausable.compact | 4 + .../utils/src/test/mocks/MockUtils.compact | 10 ++ .../test/simulators/InitializableSimulator.ts | 25 +++++ .../src/test/simulators/PausableSimulator.ts | 35 +++++++ .../src/test/simulators/UtilsSimulator.ts | 29 ++++++ contracts/utils/src/test/types/index.ts | 1 - contracts/utils/src/test/utils.test.ts | 15 +++ contracts/utils/src/test/utils/index.ts | 4 - contracts/utils/src/test/utils/test.ts | 2 +- contracts/utils/src/witnesses/index.ts | 2 - 35 files changed, 189 insertions(+), 419 deletions(-) delete mode 100644 contracts/erc20/src/test/simulators/index.ts delete mode 100644 contracts/erc20/src/witnesses/index.ts delete mode 100644 contracts/initializable/src/Initializable.compact delete mode 100644 contracts/initializable/src/MockInitializable.compact delete mode 100644 contracts/initializable/src/test/InitializableSimulator.ts delete mode 100644 contracts/initializable/src/test/initializable.test.ts delete mode 100644 contracts/initializable/src/test/types/index.ts delete mode 100644 contracts/initializable/src/test/types/test.ts delete mode 100644 contracts/initializable/src/test/utils/index.ts delete mode 100644 contracts/initializable/src/test/utils/test.ts delete mode 100644 contracts/initializable/src/witnesses/InitializableWitnesses.ts delete mode 100644 contracts/initializable/src/witnesses/index.ts delete mode 100644 contracts/initializable/tsconfig.build.json delete mode 100644 contracts/initializable/tsconfig.json delete mode 100644 contracts/utils/src/MockUtils.compact delete mode 100644 contracts/utils/src/test/UtilsSimulator.ts delete mode 100644 contracts/utils/src/test/types/index.ts delete mode 100644 contracts/utils/src/test/utils/index.ts delete mode 100644 contracts/utils/src/witnesses/index.ts diff --git a/contracts/erc20/src/test/erc20.test.ts b/contracts/erc20/src/test/erc20.test.ts index 939f1c2b..b2e57c8c 100644 --- a/contracts/erc20/src/test/erc20.test.ts +++ b/contracts/erc20/src/test/erc20.test.ts @@ -1,6 +1,6 @@ import { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; -import { ERC20Simulator } from './simulators'; -import { MaybeString } from './types'; +import { ERC20Simulator } from './simulators/ERC20Simulator'; +import { MaybeString } from './types/string'; import * as utils from './utils'; const NO_STRING: MaybeString = { @@ -96,7 +96,7 @@ describe('ERC20', () => { caller = OWNER; const txSuccess = token.transfer(Z_RECIPIENT, partialAmt, caller); - expect(txSuccess).toBeTruthy(); + expect(txSuccess).toBe(true); expect(token.balanceOf(Z_OWNER)).toEqual(1n); expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); }); @@ -105,7 +105,7 @@ describe('ERC20', () => { caller = OWNER; const txSuccess = token.transfer(Z_RECIPIENT, AMOUNT, caller); - expect(txSuccess).toBeTruthy(); + expect(txSuccess).toBe(true); expect(token.balanceOf(Z_OWNER)).toEqual(0n); expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); }); @@ -137,7 +137,7 @@ describe('ERC20', () => { it('should allow transfer of 0 tokens', () => { const txSuccess = token.transfer(Z_RECIPIENT, 0n, caller); - expect(txSuccess).toBeTruthy(); + expect(txSuccess).toBe(true); expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); }); @@ -233,7 +233,7 @@ describe('ERC20', () => { const partialAmt = AMOUNT - 1n; const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, partialAmt, caller); - expect(txSuccess).toBeTruthy(); + expect(txSuccess).toBe(true); // Check balances expect(token.balanceOf(Z_OWNER)).toEqual(1n); @@ -246,7 +246,7 @@ describe('ERC20', () => { caller = SPENDER; const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - expect(txSuccess).toBeTruthy(); + expect(txSuccess).toBe(true); // Check balances expect(token.balanceOf(Z_OWNER)).toEqual(0n); @@ -261,7 +261,7 @@ describe('ERC20', () => { caller = SPENDER; const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - expect(txSuccess).toBeTruthy(); + expect(txSuccess).toBe(true); // Check balances expect(token.balanceOf(Z_OWNER)).toEqual(0n); diff --git a/contracts/erc20/src/test/simulators/ERC20Simulator.ts b/contracts/erc20/src/test/simulators/ERC20Simulator.ts index a8e324da..c2f35e5e 100644 --- a/contracts/erc20/src/test/simulators/ERC20Simulator.ts +++ b/contracts/erc20/src/test/simulators/ERC20Simulator.ts @@ -15,9 +15,9 @@ import { ZswapCoinPublicKey, ContractAddress, } from '../../artifacts/MockERC20/contract/index.cjs'; // Combined imports -import { MaybeString } from '../types'; -import type { IContractSimulator } from './../types'; -import { ERC20PrivateState, ERC20Witnesses } from '../../witnesses'; +import { MaybeString } from '../types/string'; +import type { IContractSimulator } from './../types/test'; +import { ERC20PrivateState, ERC20Witnesses } from '../../witnesses/ERC20Witnesses'; /** * @description A simulator implementation of an erc20 contract for testing purposes. diff --git a/contracts/erc20/src/test/simulators/index.ts b/contracts/erc20/src/test/simulators/index.ts deleted file mode 100644 index 134f9c95..00000000 --- a/contracts/erc20/src/test/simulators/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { ERC20Simulator } from './ERC20Simulator'; diff --git a/contracts/erc20/src/test/utils/test.ts b/contracts/erc20/src/test/utils/test.ts index 9fd2d4f6..0a967d12 100644 --- a/contracts/erc20/src/test/utils/test.ts +++ b/contracts/erc20/src/test/utils/test.ts @@ -6,7 +6,11 @@ import { QueryContext, emptyZswapLocalState, } from '@midnight-ntwrk/compact-runtime'; +<<<<<<< HEAD import type { IContractSimulator } from '../types/test.js'; +======= +import type { IContractSimulator } from '../types/test'; +>>>>>>> b6f5215 (Add pausable (#22)) /** * Constructs a `CircuitContext` from the given state and sender information. diff --git a/contracts/erc20/src/witnesses/index.ts b/contracts/erc20/src/witnesses/index.ts deleted file mode 100644 index dc29bf8e..00000000 --- a/contracts/erc20/src/witnesses/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../artifacts/erc20/contract/index.cjs'; -export * from './ERC20Witnesses.js'; diff --git a/contracts/initializable/src/Initializable.compact b/contracts/initializable/src/Initializable.compact deleted file mode 100644 index 648f7670..00000000 --- a/contracts/initializable/src/Initializable.compact +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma language_version >= 0.14.0; - -/** - * @module Initializable - * @description Initializable provides a simple mechanism that mimics the functionality of a constructor. - */ -module Initializable{ - import CompactStandardLibrary; - - export enum STATE { uninitialized, initialized } - - export ledger state: STATE; - - /** - * @description Initializes the state thus ensuring the calling circuit can only be called once. - * - * @returns None. - */ - export circuit initialize(): [] { - assert state == STATE.uninitialized "Contract already initialized"; - state = STATE.initialized; - } - - /** - * @description Returns true if the state is initialized. - * - * @returns {Boolean} - whether the contract has been initialized. - */ - export circuit isInitialized(): Boolean { - return (state == STATE.initialized); - } -} diff --git a/contracts/initializable/src/MockInitializable.compact b/contracts/initializable/src/MockInitializable.compact deleted file mode 100644 index d670f6d9..00000000 --- a/contracts/initializable/src/MockInitializable.compact +++ /dev/null @@ -1,14 +0,0 @@ -pragma language_version >= 0.14.0; - -import CompactStandardLibrary; -import Initializable prefix Initializable_; - -export { Initializable_state, Initializable_STATE }; - -export circuit initialize(): [] { - return Initializable_initialize(); -} - -export circuit isInitialized(): Boolean { - return Initializable_isInitialized(); -} diff --git a/contracts/initializable/src/test/InitializableSimulator.ts b/contracts/initializable/src/test/InitializableSimulator.ts deleted file mode 100644 index 89402a19..00000000 --- a/contracts/initializable/src/test/InitializableSimulator.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { type CircuitContext, type ContractState, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; -import { Contract as MockInitializable, type Ledger, ledger } from '../artifacts/MockInitializable/contract/index.cjs'; -import type { IContractSimulator } from './types'; -import { InitializablePrivateState, InitializableWitnesses } from '../witnesses'; - -/** - * @description A simulator implementation of an utils contract for testing purposes. - * @template P - The private state type, fixed to UtilsPrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. - */ -export class InitializableSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockInitializable; - - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor() { - this.contract = new MockInitializable( - InitializableWitnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)) - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type UtilsPrivateState. - */ - public getCurrentPrivateState(): InitializablePrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; - } - - /** - * @description Initializes the state. - * @returns None. - */ - public initialize() { - this.circuitContext = this.contract.impureCircuits.initialize(this.circuitContext).context; - } - - /** - * @description Returns true if the state is initialized. - * @returns Whether the contract has been initialized. - */ - public isInitialized(): boolean { - return this.contract.impureCircuits.isInitialized(this.circuitContext).result; - } -} diff --git a/contracts/initializable/src/test/initializable.test.ts b/contracts/initializable/src/test/initializable.test.ts deleted file mode 100644 index 15ee059c..00000000 --- a/contracts/initializable/src/test/initializable.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { it, describe, expect } from '@jest/globals'; -import { InitializableSimulator } from './InitializableSimulator.js'; -import { Initializable_STATE as STATE } from '../artifacts/MockInitializable/contract/index.cjs'; - -const contract = new InitializableSimulator(); - -describe('Initializable', () => { - it('should generate the initial ledger state deterministically', () => { - const contract2 = new InitializableSimulator(); - expect(contract.getCurrentPublicState()).toEqual(contract2.getCurrentPublicState()); - }); - - describe('initialize', () => { - it('should not be initialized', () => { - expect(contract.isInitialized()).toEqual(false); - expect(contract.getCurrentPublicState().initializableState).toEqual(STATE.uninitialized); - }); - - it('should initialize', () => { - contract.initialize(); - expect(contract.isInitialized()).toEqual(true); - expect(contract.getCurrentPublicState().initializableState).toEqual(STATE.initialized); - }); - }); - - it('should fail when re-initialized', () => { - expect(() => { - contract.initialize(); - contract.initialize(); - }).toThrow('Contract already initialized'); - }); -}); diff --git a/contracts/initializable/src/test/types/index.ts b/contracts/initializable/src/test/types/index.ts deleted file mode 100644 index db642b5e..00000000 --- a/contracts/initializable/src/test/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { IContractSimulator } from './test'; diff --git a/contracts/initializable/src/test/types/test.ts b/contracts/initializable/src/test/types/test.ts deleted file mode 100644 index 10fb6c98..00000000 --- a/contracts/initializable/src/test/types/test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; - -/** - * Generic interface for mock contract implementations. - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - */ -export interface IContractSimulator { - /** The contract's deployed address. */ - readonly contractAddress: string; - - /** The current circuit context. */ - circuitContext: CircuitContext

; - - /** Retrieves the current ledger state. */ - getCurrentPublicState(): L; - - /** Retrieves the current private state. */ - getCurrentPrivateState(): P; - - /** Retrieves the current contract state. */ - getCurrentContractState(): ContractState; -} diff --git a/contracts/initializable/src/test/utils/index.ts b/contracts/initializable/src/test/utils/index.ts deleted file mode 100644 index 14e02ef2..00000000 --- a/contracts/initializable/src/test/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { useCircuitContext as circuitContext } from './test'; diff --git a/contracts/initializable/src/test/utils/test.ts b/contracts/initializable/src/test/utils/test.ts deleted file mode 100644 index 5a9e5837..00000000 --- a/contracts/initializable/src/test/utils/test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - QueryContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types'; - -/** - * Constructs a `CircuitContext` from the given state and sender information. - * - * This is typically used at runtime to provide the necessary context - * for executing circuits, including contract state, private state, - * sender identity, and transaction data. - * - * @template P - The type of the contract's private state. - * @param privateState - The current private state of the contract. - * @param contractState - The full contract state, including public and private data. - * @param sender - The public key of the sender (used in the circuit). - * @param contractAddress - The address of the deployed contract. - * @returns A fully populated `CircuitContext` for circuit execution. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContext

( - privateState: P, - contractState: ContractState, - sender: CoinPublicKey, - contractAddress: ContractAddress, -): CircuitContext

{ - return { - originalState: contractState, - currentPrivateState: privateState, - transactionContext: new QueryContext(contractState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} - -/** - * Prepares a new `CircuitContext` using the given sender and contract. - * - * Useful for mocking or updating the circuit context with a custom sender. - * - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - * @template C - The specific type of the contract implementing `MockContract`. - * @param contract - The contract instance implementing `MockContract`. - * @param sender - The public key to set as the sender in the new circuit context. - * @returns A new `CircuitContext` with the sender and updated context values. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContextSender>( - contract: C, - sender: CoinPublicKey, -): CircuitContext

{ - const currentPrivateState = contract.getCurrentPrivateState(); - const originalState = contract.getCurrentContractState(); - const contractAddress = contract.contractAddress; - - return { - originalState, - currentPrivateState, - transactionContext: new QueryContext(originalState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} diff --git a/contracts/initializable/src/witnesses/InitializableWitnesses.ts b/contracts/initializable/src/witnesses/InitializableWitnesses.ts deleted file mode 100644 index 9d99cd04..00000000 --- a/contracts/initializable/src/witnesses/InitializableWitnesses.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This is how we type an empty object. -export type InitializablePrivateState = Record; -export const InitializableWitnesses = {}; diff --git a/contracts/initializable/src/witnesses/index.ts b/contracts/initializable/src/witnesses/index.ts deleted file mode 100644 index d27dd4c3..00000000 --- a/contracts/initializable/src/witnesses/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../artifacts/initializable/contract/index.cjs'; -export * from './InitializableWitnesses'; diff --git a/contracts/initializable/tsconfig.build.json b/contracts/initializable/tsconfig.build.json deleted file mode 100644 index f1132509..00000000 --- a/contracts/initializable/tsconfig.build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["src/test/**/*.ts"], - "compilerOptions": {} -} diff --git a/contracts/initializable/tsconfig.json b/contracts/initializable/tsconfig.json deleted file mode 100644 index d6c626dc..00000000 --- a/contracts/initializable/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "include": ["src/**/*.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - "declaration": true, - "lib": ["ES2022"], - "target": "ES2022", - "module": "nodenext", - "moduleResolution": "nodenext", - "allowJs": true, - "forceConsistentCasingInFileNames": true, - "noImplicitAny": true, - "strict": true, - "isolatedModules": true, - "sourceMap": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "skipLibCheck": true - } -} \ No newline at end of file diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 5408a32e..905c5d18 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -14,6 +14,7 @@ } }, "scripts": { +<<<<<<< HEAD "compact": "compact-compiler", "build": "compact-builder && tsc", "test": "vitest run", @@ -25,6 +26,14 @@ }, "dependencies": { "@openzeppelin-midnight/compact": "workspace:^" +======= + "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", + "test": "NODE_OPTIONS=--experimental-vm-modules jest", + "prepack": "yarn build", + "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/{Initializable,Pausable,Utils}.compact ./dist", + "lint": "eslint src", + "typecheck": "tsc -p tsconfig.json --noEmit" +>>>>>>> b6f5215 (Add pausable (#22)) }, "devDependencies": { "@biomejs/biome": "1.9.4", diff --git a/contracts/utils/src/Initializable.compact b/contracts/utils/src/Initializable.compact index 99a2c0e1..3e55ceea 100644 --- a/contracts/utils/src/Initializable.compact +++ b/contracts/utils/src/Initializable.compact @@ -1,5 +1,9 @@ // SPDX-License-Identifier: MIT +<<<<<<< HEAD pragma language_version >= 0.15.0; +======= +pragma language_version >= 0.14.0; +>>>>>>> b6f5215 (Add pausable (#22)) /** * @module Initializable diff --git a/contracts/utils/src/MockUtils.compact b/contracts/utils/src/MockUtils.compact deleted file mode 100644 index f2263768..00000000 --- a/contracts/utils/src/MockUtils.compact +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.14.0; - -import CompactStandardLibrary; - -import Utils prefix Utils_; - -export { ZswapCoinPublicKey, ContractAddress, Either }; - -export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { - return Utils_isKeyOrAddressZero(keyOrAddress); -} diff --git a/contracts/utils/src/Pausable.compact b/contracts/utils/src/Pausable.compact index 11e0ba04..4ed622d8 100644 --- a/contracts/utils/src/Pausable.compact +++ b/contracts/utils/src/Pausable.compact @@ -1,5 +1,9 @@ // SPDX-License-Identifier: MIT +<<<<<<< HEAD pragma language_version >= 0.15.0; +======= +pragma language_version >= 0.14.0; +>>>>>>> b6f5215 (Add pausable (#22)) /** * @module Pausable diff --git a/contracts/utils/src/test/Initializable.test.ts b/contracts/utils/src/test/Initializable.test.ts index a3bb2eba..19c29371 100644 --- a/contracts/utils/src/test/Initializable.test.ts +++ b/contracts/utils/src/test/Initializable.test.ts @@ -1,5 +1,10 @@ +<<<<<<< HEAD import { beforeEach, describe, expect, it } from 'vitest'; import { InitializableSimulator } from './simulators/InitializableSimulator.js'; +======= +import { it, describe, expect } from '@jest/globals'; +import { InitializableSimulator } from './simulators/InitializableSimulator'; +>>>>>>> b6f5215 (Add pausable (#22)) let initializable: InitializableSimulator; @@ -10,20 +15,29 @@ describe('Initializable', () => { it('should generate the initial ledger state deterministically', () => { const initializable2 = new InitializableSimulator(); +<<<<<<< HEAD expect(initializable.getCurrentPublicState()).toEqual( initializable2.getCurrentPublicState(), ); +======= + expect(initializable.getCurrentPublicState()).toEqual(initializable2.getCurrentPublicState()); +>>>>>>> b6f5215 (Add pausable (#22)) }); describe('initialize', () => { it('should not be initialized', () => { +<<<<<<< HEAD expect( initializable.getCurrentPublicState().initializable_IsInitialized, ).toEqual(false); +======= + expect(initializable.getCurrentPublicState().initializable_IsInitialized).toEqual(false); +>>>>>>> b6f5215 (Add pausable (#22)) }); it('should initialize', () => { initializable.initialize(); +<<<<<<< HEAD expect( initializable.getCurrentPublicState().initializable_IsInitialized, ).toEqual(true); @@ -35,6 +49,17 @@ describe('Initializable', () => { initializable.initialize(); initializable.initialize(); }).toThrow('Initializable: contract already initialized'); +======= + expect(initializable.getCurrentPublicState().initializable_IsInitialized).toEqual(true); + }); + }); + + it('should fail when re-initialized', () => { + expect(() => { + initializable.initialize(); + initializable.initialize(); + }).toThrow('Initializable: contract already initialized'); +>>>>>>> b6f5215 (Add pausable (#22)) }); describe('assertInitialized', () => { diff --git a/contracts/utils/src/test/Pausable.test.ts b/contracts/utils/src/test/Pausable.test.ts index 94662b0c..ebd0b27f 100644 --- a/contracts/utils/src/test/Pausable.test.ts +++ b/contracts/utils/src/test/Pausable.test.ts @@ -1,5 +1,10 @@ +<<<<<<< HEAD import { beforeEach, describe, expect, it } from 'vitest'; import { PausableSimulator } from './simulators/PausableSimulator.js'; +======= +import { it, describe, expect } from '@jest/globals'; +import { PausableSimulator } from './simulators/PausableSimulator'; +>>>>>>> b6f5215 (Add pausable (#22)) let pausable: PausableSimulator; @@ -41,7 +46,11 @@ describe('Pausable', () => { }); it('should not throw when calling assertPaused', () => { +<<<<<<< HEAD pausable.assertPaused(); +======= + pausable.assertPaused(); +>>>>>>> b6f5215 (Add pausable (#22)) }); it('should throw when calling assertNotPaused', () => { diff --git a/contracts/utils/src/test/UtilsSimulator.ts b/contracts/utils/src/test/UtilsSimulator.ts deleted file mode 100644 index c55c802f..00000000 --- a/contracts/utils/src/test/UtilsSimulator.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { - type CircuitContext, - type ContractState, - QueryContext, - constructorContext, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; -import { - type Ledger, - Contract as MockUtils, - ledger, - Either, - ZswapCoinPublicKey, - ContractAddress, -} from '../artifacts/MockUtils/contract/index.cjs'; // Combined imports -import type { IContractSimulator } from './types'; -import { UtilsPrivateState, UtilsWitnesses } from '../witnesses'; - -/** - * @description A simulator implementation of an utils contract for testing purposes. - * @template P - The private state type, fixed to UtilsPrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. - */ -export class UtilsContractSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockUtils; - - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor() { - this.contract = new MockUtils( - UtilsWitnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)) - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type UtilsPrivateState. - */ - public getCurrentPrivateState(): UtilsPrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; - } - - /** - * @description Returns whether `keyOrAddress` is the zero address. - * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. - * @returns Returns true if `keyOrAddress` is zero. - */ - public isKeyOrAddressZero(keyOrAddress: Either): boolean { - return this.contract.circuits.isKeyOrAddressZero(this.circuitContext, keyOrAddress).result; - } -} diff --git a/contracts/utils/src/test/mocks/MockInitializable.compact b/contracts/utils/src/test/mocks/MockInitializable.compact index 99a07dc8..6ae7561b 100644 --- a/contracts/utils/src/test/mocks/MockInitializable.compact +++ b/contracts/utils/src/test/mocks/MockInitializable.compact @@ -1,4 +1,8 @@ +<<<<<<< HEAD pragma language_version >= 0.15.0; +======= +pragma language_version >= 0.14.0; +>>>>>>> b6f5215 (Add pausable (#22)) import CompactStandardLibrary; import "../../Initializable" prefix Initializable_; diff --git a/contracts/utils/src/test/mocks/MockPausable.compact b/contracts/utils/src/test/mocks/MockPausable.compact index 17e26bb6..60351ca2 100644 --- a/contracts/utils/src/test/mocks/MockPausable.compact +++ b/contracts/utils/src/test/mocks/MockPausable.compact @@ -1,4 +1,8 @@ +<<<<<<< HEAD pragma language_version >= 0.15.0; +======= +pragma language_version >= 0.14.0; +>>>>>>> b6f5215 (Add pausable (#22)) import CompactStandardLibrary; import "../../Pausable" prefix Pausable_; diff --git a/contracts/utils/src/test/mocks/MockUtils.compact b/contracts/utils/src/test/mocks/MockUtils.compact index eaeb3d18..b559380f 100644 --- a/contracts/utils/src/test/mocks/MockUtils.compact +++ b/contracts/utils/src/test/mocks/MockUtils.compact @@ -1,4 +1,10 @@ +<<<<<<< HEAD pragma language_version >= 0.15.0; +======= +// SPDX-License-Identifier: MIT + +pragma language_version >= 0.14.0; +>>>>>>> b6f5215 (Add pausable (#22)) import CompactStandardLibrary; @@ -7,6 +13,7 @@ import "../../Utils" prefix Utils_; export { ZswapCoinPublicKey, ContractAddress, Either }; export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { +<<<<<<< HEAD return Utils_isKeyOrAddressZero(keyOrAddress); } @@ -27,4 +34,7 @@ export pure circuit isContractAddress(keyOrAddress: Either { return Utils_emptyString(); +======= + return Utils_isKeyOrAddressZero(keyOrAddress); +>>>>>>> b6f5215 (Add pausable (#22)) } diff --git a/contracts/utils/src/test/simulators/InitializableSimulator.ts b/contracts/utils/src/test/simulators/InitializableSimulator.ts index e2cfa376..81a01d3a 100644 --- a/contracts/utils/src/test/simulators/InitializableSimulator.ts +++ b/contracts/utils/src/test/simulators/InitializableSimulator.ts @@ -1,3 +1,4 @@ +<<<<<<< HEAD import { type CircuitContext, type ContractState, @@ -15,6 +16,12 @@ import { InitializableWitnesses, } from '../../witnesses/InitializableWitnesses.js'; import type { IContractSimulator } from '../types/test.js'; +======= +import { type CircuitContext, type ContractState, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; +import { Contract as MockInitializable, type Ledger, ledger } from '../../artifacts/MockInitializable/contract/index.cjs'; +import type { IContractSimulator } from '../types/test'; +import { InitializablePrivateState, InitializableWitnesses } from '../../witnesses/InitializableWitnesses'; +>>>>>>> b6f5215 (Add pausable (#22)) /** * @description A simulator implementation of an utils contract for testing purposes. @@ -44,7 +51,13 @@ export class InitializableSimulator currentPrivateState, currentContractState, currentZswapLocalState, +<<<<<<< HEAD } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); +======= + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)) + ); +>>>>>>> b6f5215 (Add pausable (#22)) this.circuitContext = { currentPrivateState, currentZswapLocalState, @@ -86,9 +99,13 @@ export class InitializableSimulator * @returns None. */ public initialize() { +<<<<<<< HEAD this.circuitContext = this.contract.impureCircuits.initialize( this.circuitContext, ).context; +======= + this.circuitContext = this.contract.impureCircuits.initialize(this.circuitContext).context; +>>>>>>> b6f5215 (Add pausable (#22)) } /** @@ -97,8 +114,12 @@ export class InitializableSimulator * @throws Will throw "Initializable: contract not initialized" if the contract is not initialized. */ public assertInitialized() { +<<<<<<< HEAD return this.contract.impureCircuits.assertInitialized(this.circuitContext) .result; +======= + return this.contract.impureCircuits.assertInitialized(this.circuitContext).result; +>>>>>>> b6f5215 (Add pausable (#22)) } /** @@ -107,8 +128,12 @@ export class InitializableSimulator * @throws Will throw "Initializable: contract already initialized" if the contract is already initialized. */ public assertNotInitialized() { +<<<<<<< HEAD return this.contract.impureCircuits.assertNotInitialized( this.circuitContext, ).result; +======= + return this.contract.impureCircuits.assertNotInitialized(this.circuitContext).result; +>>>>>>> b6f5215 (Add pausable (#22)) } } diff --git a/contracts/utils/src/test/simulators/PausableSimulator.ts b/contracts/utils/src/test/simulators/PausableSimulator.ts index cbec7204..e80dcb96 100644 --- a/contracts/utils/src/test/simulators/PausableSimulator.ts +++ b/contracts/utils/src/test/simulators/PausableSimulator.ts @@ -1,3 +1,4 @@ +<<<<<<< HEAD import { type CircuitContext, type ContractState, @@ -15,6 +16,12 @@ import { PausableWitnesses, } from '../../witnesses/PausableWitnesses.js'; import type { IContractSimulator } from '../types/test.js'; +======= +import { type CircuitContext, type ContractState, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; +import { Contract as MockPausable, type Ledger, ledger } from '../../artifacts/MockPausable/contract/index.cjs'; +import type { IContractSimulator } from '../types/test'; +import { PausablePrivateState, PausableWitnesses } from '../../witnesses/PausableWitnesses'; +>>>>>>> b6f5215 (Add pausable (#22)) /** * @description A simulator implementation of an utils contract for testing purposes. @@ -37,12 +44,24 @@ export class PausableSimulator * @description Initializes the mock contract. */ constructor() { +<<<<<<< HEAD this.contract = new MockPausable(PausableWitnesses); +======= + this.contract = new MockPausable( + PausableWitnesses, + ); +>>>>>>> b6f5215 (Add pausable (#22)) const { currentPrivateState, currentContractState, currentZswapLocalState, +<<<<<<< HEAD } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); +======= + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)) + ); +>>>>>>> b6f5215 (Add pausable (#22)) this.circuitContext = { currentPrivateState, currentZswapLocalState, @@ -92,9 +111,13 @@ export class PausableSimulator * @returns None. */ public assertPaused() { +<<<<<<< HEAD this.circuitContext = this.contract.impureCircuits.assertPaused( this.circuitContext, ).context; +======= + this.circuitContext = this.contract.impureCircuits.assertPaused(this.circuitContext).context; +>>>>>>> b6f5215 (Add pausable (#22)) } /** @@ -102,9 +125,13 @@ export class PausableSimulator * @returns None. */ public assertNotPaused() { +<<<<<<< HEAD this.circuitContext = this.contract.impureCircuits.assertNotPaused( this.circuitContext, ).context; +======= + this.circuitContext = this.contract.impureCircuits.assertNotPaused(this.circuitContext).context; +>>>>>>> b6f5215 (Add pausable (#22)) } /** @@ -112,9 +139,13 @@ export class PausableSimulator * @returns None. */ public pause() { +<<<<<<< HEAD this.circuitContext = this.contract.impureCircuits.pause( this.circuitContext, ).context; +======= + this.circuitContext = this.contract.impureCircuits.pause(this.circuitContext).context; +>>>>>>> b6f5215 (Add pausable (#22)) } /** @@ -122,8 +153,12 @@ export class PausableSimulator * @returns None. */ public unpause() { +<<<<<<< HEAD this.circuitContext = this.contract.impureCircuits.unpause( this.circuitContext, ).context; +======= + this.circuitContext = this.contract.impureCircuits.unpause(this.circuitContext).context; +>>>>>>> b6f5215 (Add pausable (#22)) } } diff --git a/contracts/utils/src/test/simulators/UtilsSimulator.ts b/contracts/utils/src/test/simulators/UtilsSimulator.ts index 4a607c7a..6de40832 100644 --- a/contracts/utils/src/test/simulators/UtilsSimulator.ts +++ b/contracts/utils/src/test/simulators/UtilsSimulator.ts @@ -6,6 +6,7 @@ import { } from '@midnight-ntwrk/compact-runtime'; import { sampleContractAddress } from '@midnight-ntwrk/zswap'; import { +<<<<<<< HEAD type ContractAddress, type Either, type Ledger, @@ -18,6 +19,17 @@ import { UtilsWitnesses, } from '../../witnesses/UtilsWitnesses.js'; import type { IContractSimulator } from '../types/test.js'; +======= + type Ledger, + Contract as MockUtils, + ledger, + Either, + ZswapCoinPublicKey, + ContractAddress, +} from '../../artifacts/MockUtils/contract/index.cjs'; // Combined imports +import type { IContractSimulator } from '../types/test'; +import { UtilsPrivateState, UtilsWitnesses } from '../../witnesses/UtilsWitnesses'; +>>>>>>> b6f5215 (Add pausable (#22)) /** * @description A simulator implementation of an utils contract for testing purposes. @@ -40,12 +52,24 @@ export class UtilsSimulator * @description Initializes the mock contract. */ constructor() { +<<<<<<< HEAD this.contract = new MockUtils(UtilsWitnesses); +======= + this.contract = new MockUtils( + UtilsWitnesses, + ); +>>>>>>> b6f5215 (Add pausable (#22)) const { currentPrivateState, currentContractState, currentZswapLocalState, +<<<<<<< HEAD } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); +======= + } = this.contract.initialState( + constructorContext({}, '0'.repeat(64)) + ); +>>>>>>> b6f5215 (Add pausable (#22)) this.circuitContext = { currentPrivateState, currentZswapLocalState, @@ -87,6 +111,7 @@ export class UtilsSimulator * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @returns Returns true if `keyOrAddress` is zero. */ +<<<<<<< HEAD public isKeyOrAddressZero( keyOrAddress: Either, ): boolean { @@ -145,5 +170,9 @@ export class UtilsSimulator */ public emptyString(): string { return this.contract.circuits.emptyString(this.circuitContext).result; +======= + public isKeyOrAddressZero(keyOrAddress: Either): boolean { + return this.contract.circuits.isKeyOrAddressZero(this.circuitContext, keyOrAddress).result; +>>>>>>> b6f5215 (Add pausable (#22)) } } diff --git a/contracts/utils/src/test/types/index.ts b/contracts/utils/src/test/types/index.ts deleted file mode 100644 index db642b5e..00000000 --- a/contracts/utils/src/test/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { IContractSimulator } from './test'; diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 7ff600f7..33214ba5 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -1,6 +1,11 @@ +<<<<<<< HEAD import { describe, expect, it } from 'vitest'; import { UtilsSimulator } from './simulators/UtilsSimulator.js'; import * as contractUtils from './utils/address.js'; +======= +import { UtilsSimulator } from './simulators/UtilsSimulator'; +import * as contractUtils from './utils/address'; +>>>>>>> b6f5215 (Add pausable (#22)) const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); @@ -9,8 +14,11 @@ const SOME_CONTRACT = const OTHER_CONTRACT = contractUtils.createEitherTestContractAddress('OTHER_CONTRACT'); +<<<<<<< HEAD const EMPTY_STRING = ''; +======= +>>>>>>> b6f5215 (Add pausable (#22)) let contract: UtilsSimulator; describe('Utils', () => { @@ -19,14 +27,19 @@ describe('Utils', () => { describe('isKeyOrAddressZero', () => { it('should return zero for the zero address', () => { expect(contract.isKeyOrAddressZero(contractUtils.ZERO_KEY)).toBe(true); +<<<<<<< HEAD expect(contract.isKeyOrAddressZero(contractUtils.ZERO_ADDRESS)).toBe( true, ); +======= + expect(contract.isKeyOrAddressZero(contractUtils.ZERO_ADDRESS)).toBe(true); +>>>>>>> b6f5215 (Add pausable (#22)) }); it('should not return zero for nonzero addresses', () => { expect(contract.isKeyOrAddressZero(Z_SOME_KEY)).toBe(false); expect(contract.isKeyOrAddressZero(SOME_CONTRACT)).toBe(false); +<<<<<<< HEAD }); }); @@ -91,6 +104,8 @@ describe('Utils', () => { describe('emptyString', () => { it('should return the empty string', () => { expect(contract.emptyString()).toBe(EMPTY_STRING); +======= +>>>>>>> b6f5215 (Add pausable (#22)) }); }); }); diff --git a/contracts/utils/src/test/utils/index.ts b/contracts/utils/src/test/utils/index.ts deleted file mode 100644 index 2668cc79..00000000 --- a/contracts/utils/src/test/utils/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { useCircuitContext as circuitContext } from './test'; -export { - pad, encodeToPK, encodeToAddress, createEitherTestUser, createEitherTestContractAddress, ZERO_KEY, ZERO_ADDRESS -} from './address'; diff --git a/contracts/utils/src/test/utils/test.ts b/contracts/utils/src/test/utils/test.ts index 940ed612..a8840104 100644 --- a/contracts/utils/src/test/utils/test.ts +++ b/contracts/utils/src/test/utils/test.ts @@ -6,7 +6,7 @@ import { QueryContext, emptyZswapLocalState, } from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types'; +import type { IContractSimulator } from '../types/test'; /** * Constructs a `CircuitContext` from the given state and sender information. diff --git a/contracts/utils/src/witnesses/index.ts b/contracts/utils/src/witnesses/index.ts deleted file mode 100644 index 1c74ba34..00000000 --- a/contracts/utils/src/witnesses/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../artifacts/utils/contract/index.cjs'; -export * from './UtilsWitnesses.js'; From 2257d617e6e9543ca0ac74ccbe9ec378b779a6c9 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 29 Apr 2025 16:36:52 -0500 Subject: [PATCH 269/282] Bump midnight-js, transition to biome, basic improvements (#35) * bump midnight-js * remove unused deps * remove eslint and prettier, add biome * run fmt * run lint * organize imports * remove dev deps from contracts/ * remove unused deps * update turbo and scripts * add clean script * add clean script * clean up test config * remove jest reporters * bump turbo to 2.5 * bump turbo * fix package names --- biome.json | 6 +- compact/turbo.json | 19 ++- contracts/erc20/.eslintignore | 1 - contracts/erc20/.eslintrc.cjs | 30 ---- contracts/erc20/jest.config.ts | 28 ++-- contracts/erc20/js-resolver.cjs | 18 ++- contracts/erc20/package.json | 19 ++- contracts/erc20/src/ERC20.compact | 2 +- contracts/erc20/src/test/erc20.test.ts | 64 ++++++--- .../src/test/simulators/ERC20Simulator.ts | 133 +++++++++++++----- contracts/erc20/src/test/utils/address.ts | 35 ++--- contracts/utils/package.json | 11 +- .../utils/src/test/Initializable.test.ts | 25 ---- .../test/simulators/InitializableSimulator.ts | 3 +- .../src/test/simulators/PausableSimulator.ts | 47 +------ .../src/test/simulators/UtilsSimulator.ts | 8 +- contracts/utils/src/test/types/test.ts | 5 +- contracts/utils/src/test/utils/address.ts | 3 +- contracts/utils/src/test/utils/index.ts | 10 ++ contracts/utils/src/test/utils/test.ts | 21 +-- turbo.json | 41 ++++-- 21 files changed, 271 insertions(+), 258 deletions(-) delete mode 100644 contracts/erc20/.eslintignore delete mode 100644 contracts/erc20/.eslintrc.cjs create mode 100644 contracts/utils/src/test/utils/index.ts diff --git a/biome.json b/biome.json index 5e4b9777..10c26977 100644 --- a/biome.json +++ b/biome.json @@ -21,7 +21,9 @@ "formatter": { "enabled": true, "indentStyle": "space", - "ignore": ["package.json"] + "ignore": [ + "package.json" + ] }, "organizeImports": { "enabled": true @@ -87,4 +89,4 @@ "indentStyle": "space" } } -} +} \ No newline at end of file diff --git a/compact/turbo.json b/compact/turbo.json index 5d208997..3133543c 100644 --- a/compact/turbo.json +++ b/compact/turbo.json @@ -1,12 +1,21 @@ { "$schema": "https://turbo.build/schema.json", - "extends": ["//"], + "extends": [ + "//" + ], "tasks": { "build": { - "outputs": ["dist/**"], - "inputs": ["src/**/*.ts", "tsconfig.json"], - "env": ["COMPACT_HOME"], + "outputs": [ + "dist/**" + ], + "inputs": [ + "src/**/*.ts", + "tsconfig.json" + ], + "env": [ + "COMPACT_HOME" + ], "cache": true } } -} +} \ No newline at end of file diff --git a/contracts/erc20/.eslintignore b/contracts/erc20/.eslintignore deleted file mode 100644 index 327555cd..00000000 --- a/contracts/erc20/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -src/artifacts diff --git a/contracts/erc20/.eslintrc.cjs b/contracts/erc20/.eslintrc.cjs deleted file mode 100644 index 581f1d49..00000000 --- a/contracts/erc20/.eslintrc.cjs +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - node: true, - jest: true, - }, - extends: [ - 'standard-with-typescript', - 'plugin:prettier/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - overrides: [], - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['tsconfig.json'], - }, - rules: { - '@typescript-eslint/no-misused-promises': 'off', // https://github.com/typescript-eslint/typescript-eslint/issues/5807 - '@typescript-eslint/no-floating-promises': 'warn', - '@typescript-eslint/promise-function-async': 'off', - '@typescript-eslint/no-redeclare': 'off', - '@typescript-eslint/no-invalid-void-type': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/consistent-type-definitions': 'off' - }, -}; diff --git a/contracts/erc20/jest.config.ts b/contracts/erc20/jest.config.ts index 3cbccc1b..bde5bde1 100644 --- a/contracts/erc20/jest.config.ts +++ b/contracts/erc20/jest.config.ts @@ -1,28 +1,16 @@ -import type { Config } from "@jest/types"; +import type { Config } from '@jest/types'; const config: Config.InitialOptions = { - preset: "ts-jest/presets/default-esm", - testEnvironment: "node", + preset: 'ts-jest/presets/default-esm', + testEnvironment: 'node', verbose: true, - roots: [""], - modulePaths: [""], + roots: [''], + modulePaths: [''], passWithNoTests: false, - testMatch: ["**/*.test.ts"], - extensionsToTreatAsEsm: [".ts"], - collectCoverage: true, + testMatch: ['**/*.test.ts'], + extensionsToTreatAsEsm: ['.ts'], + collectCoverage: false, resolver: '/js-resolver.cjs', - coverageThreshold: { - global: { - branches: 50, - functions: 50, - lines: 50, - }, - }, - reporters: [ - "default", - ["jest-junit", { outputDirectory: "reports", outputName: "report.xml" }], - ["jest-html-reporters", { publicPath: "reports", filename: "report.html" }], - ], }; export default config; diff --git a/contracts/erc20/js-resolver.cjs b/contracts/erc20/js-resolver.cjs index cc9ed285..19b6f50c 100644 --- a/contracts/erc20/js-resolver.cjs +++ b/contracts/erc20/js-resolver.cjs @@ -1,16 +1,20 @@ const jsResolver = (path, options) => { - const jsExtRegex = /\.js$/i - const resolver = options.defaultResolver - if (jsExtRegex.test(path) && !options.basedir.includes('node_modules') && !path.includes('node_modules')) { + const jsExtRegex = /\.js$/i; + const resolver = options.defaultResolver; + if ( + jsExtRegex.test(path) && + !options.basedir.includes('node_modules') && + !path.includes('node_modules') + ) { const newPath = path.replace(jsExtRegex, '.ts'); try { - return resolver(newPath, options) + return resolver(newPath, options); } catch { // use default resolver } } - return resolver(path, options) -} + return resolver(path, options); +}; -module.exports = jsResolver +module.exports = jsResolver; diff --git a/contracts/erc20/package.json b/contracts/erc20/package.json index d914daf0..c64d5517 100644 --- a/contracts/erc20/package.json +++ b/contracts/erc20/package.json @@ -1,5 +1,5 @@ { - "name": "@openzeppelin-midnight-contracts/erc20-contract", + "name": "@openzeppelin-midnight/erc20", "type": "module", "main": "dist/index.js", "module": "dist/index.js", @@ -15,18 +15,15 @@ "scripts": { "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", "test": "NODE_OPTIONS=--experimental-vm-modules jest", - "prepack": "yarn build", "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/ERC20.compact ./dist", - "lint": "eslint src", - "typecheck": "tsc -p tsconfig.json --noEmit" + "types": "tsc -p tsconfig.json --noEmit", + "fmt": "biome format", + "fmt:fix": "biome format --write", + "lint": "biome lint", + "lint:fix": "biome check --write", + "clean": "git clean -fXd" }, "dependencies": { - "@openzeppelin-midnight-contracts/utils-contract": "workspace:^" - }, - "devDependencies": { - "@midnight-ntwrk/compact": "workspace:*", - "eslint": "^8.52.0", - "jest": "^29.7.0", - "typescript": "^5.2.2" + "@openzeppelin-midnight/utils": "workspace:^" } } diff --git a/contracts/erc20/src/ERC20.compact b/contracts/erc20/src/ERC20.compact index 96bdab69..31ca0059 100644 --- a/contracts/erc20/src/ERC20.compact +++ b/contracts/erc20/src/ERC20.compact @@ -22,7 +22,7 @@ pragma language_version >= 0.14.0; */ module ERC20 { import CompactStandardLibrary; - import "../../node_modules/@openzeppelin-midnight-contracts/utils-contract/src/Utils" prefix Utils_; + import "../../node_modules/@openzeppelin-midnight/utils/src/Utils" prefix Utils_; /// Public state export sealed ledger _name: Maybe>; diff --git a/contracts/erc20/src/test/erc20.test.ts b/contracts/erc20/src/test/erc20.test.ts index b2e57c8c..8e9a4596 100644 --- a/contracts/erc20/src/test/erc20.test.ts +++ b/contracts/erc20/src/test/erc20.test.ts @@ -1,28 +1,35 @@ -import { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; +import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; import { ERC20Simulator } from './simulators/ERC20Simulator'; -import { MaybeString } from './types/string'; +import type { MaybeString } from './types/string'; import * as utils from './utils'; const NO_STRING: MaybeString = { is_some: false, - value: '' + value: '', }; const NAME: MaybeString = { is_some: true, - value: "NAME" + value: 'NAME', }; const SYMBOL: MaybeString = { is_some: true, - value: "SYMBOL" + value: 'SYMBOL', }; const DECIMALS: bigint = 18n; const AMOUNT: bigint = BigInt(250); -const MAX_UINT128 = BigInt(2**128) - BigInt(1); - -const OWNER = String(Buffer.from("OWNER", 'ascii').toString('hex')).padStart(64, '0'); -const SPENDER = String(Buffer.from("SPENDER", 'ascii').toString('hex')).padStart(64, '0'); -const UNAUTHORIZED = String(Buffer.from("UNAUTHORIZED", 'ascii').toString('hex')).padStart(64, '0'); +const MAX_UINT128 = BigInt(2 ** 128) - BigInt(1); + +const OWNER = String(Buffer.from('OWNER', 'ascii').toString('hex')).padStart( + 64, + '0', +); +const SPENDER = String( + Buffer.from('SPENDER', 'ascii').toString('hex'), +).padStart(64, '0'); +const UNAUTHORIZED = String( + Buffer.from('UNAUTHORIZED', 'ascii').toString('hex'), +).padStart(64, '0'); const ZERO = String().padStart(64, '0'); const Z_OWNER = utils.createEitherTestUser('OWNER'); const Z_RECIPIENT = utils.createEitherTestUser('RECIPIENT'); @@ -65,8 +72,8 @@ describe('ERC20', () => { it('returns the amount of existing tokens when there is a supply', () => { token._mint(Z_OWNER, AMOUNT); expect(token.totalSupply()).toEqual(AMOUNT); - }) - }) + }); + }); describe('balanceOf', () => { it('should return zero when requested account has no balance', () => { @@ -232,7 +239,12 @@ describe('ERC20', () => { caller = SPENDER; const partialAmt = AMOUNT - 1n; - const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, partialAmt, caller); + const txSuccess = token.transferFrom( + Z_OWNER, + Z_RECIPIENT, + partialAmt, + caller, + ); expect(txSuccess).toBe(true); // Check balances @@ -245,7 +257,12 @@ describe('ERC20', () => { it('should transferFrom spender (full)', () => { caller = SPENDER; - const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + const txSuccess = token.transferFrom( + Z_OWNER, + Z_RECIPIENT, + AMOUNT, + caller, + ); expect(txSuccess).toBe(true); // Check balances @@ -260,7 +277,12 @@ describe('ERC20', () => { token.approve(Z_SPENDER, MAX_UINT128, caller); caller = SPENDER; - const txSuccess = token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + const txSuccess = token.transferFrom( + Z_OWNER, + Z_RECIPIENT, + AMOUNT, + caller, + ); expect(txSuccess).toBe(true); // Check balances @@ -270,7 +292,7 @@ describe('ERC20', () => { expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(MAX_UINT128); }); - it ('should fail when transfer amount exceeds allowance', () => { + it('should fail when transfer amount exceeds allowance', () => { caller = SPENDER; expect(() => { @@ -278,7 +300,7 @@ describe('ERC20', () => { }).toThrow('ERC20: insufficient allowance'); }); - it ('should fail when transfer amount exceeds balance', () => { + it('should fail when transfer amount exceeds balance', () => { caller = OWNER; // Increase allowance > balance token.approve(Z_SPENDER, AMOUNT + 1n, caller); @@ -294,7 +316,7 @@ describe('ERC20', () => { expect(() => { token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - }).toThrow("ERC20: insufficient allowance"); + }).toThrow('ERC20: insufficient allowance'); }); it('should fail to transferFrom zero address', () => { @@ -302,7 +324,7 @@ describe('ERC20', () => { expect(() => { token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - }).toThrow("ERC20: insufficient allowance"); + }).toThrow('ERC20: insufficient allowance'); }); it('should fail to transferFrom to the zero address', () => { @@ -310,7 +332,7 @@ describe('ERC20', () => { expect(() => { token.transferFrom(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT, caller); - }).toThrow("ERC20: invalid receiver"); + }).toThrow('ERC20: invalid receiver'); }); }); @@ -330,7 +352,7 @@ describe('ERC20', () => { expect(token.balanceOf(Z_OWNER)).toEqual(1n); expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); }); - }) + }); describe('_mint', () => { it('should mint and update supply', () => { diff --git a/contracts/erc20/src/test/simulators/ERC20Simulator.ts b/contracts/erc20/src/test/simulators/ERC20Simulator.ts index c2f35e5e..3e48f543 100644 --- a/contracts/erc20/src/test/simulators/ERC20Simulator.ts +++ b/contracts/erc20/src/test/simulators/ERC20Simulator.ts @@ -1,6 +1,6 @@ import { type CircuitContext, - CoinPublicKey, + type CoinPublicKey, type ContractState, QueryContext, constructorContext, @@ -8,16 +8,19 @@ import { } from '@midnight-ntwrk/compact-runtime'; import { sampleContractAddress } from '@midnight-ntwrk/zswap'; import { + type ContractAddress, + type Either, type Ledger, Contract as MockERC20, + type ZswapCoinPublicKey, ledger, - Either, - ZswapCoinPublicKey, - ContractAddress, } from '../../artifacts/MockERC20/contract/index.cjs'; // Combined imports -import { MaybeString } from '../types/string'; +import { + type ERC20PrivateState, + ERC20Witnesses, +} from '../../witnesses/ERC20Witnesses'; +import type { MaybeString } from '../types/string'; import type { IContractSimulator } from './../types/test'; -import { ERC20PrivateState, ERC20Witnesses } from '../../witnesses/ERC20Witnesses'; /** * @description A simulator implementation of an erc20 contract for testing purposes. @@ -40,15 +43,16 @@ export class ERC20Simulator * @description Initializes the mock contract. */ constructor(name: MaybeString, symbol: MaybeString, decimals: bigint) { - this.contract = new MockERC20( - ERC20Witnesses, - ); + this.contract = new MockERC20(ERC20Witnesses); const { currentPrivateState, currentContractState, currentZswapLocalState, } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)), name, symbol, decimals, + constructorContext({}, '0'.repeat(64)), + name, + symbol, + decimals, ); this.circuitContext = { currentPrivateState, @@ -123,8 +127,11 @@ export class ERC20Simulator * @param account The public key or contract address to query. * @returns The account's token balance. */ - public balanceOf(account: Either): bigint { - return this.contract.impureCircuits.balanceOf(this.circuitContext, account).result; + public balanceOf( + account: Either, + ): bigint { + return this.contract.impureCircuits.balanceOf(this.circuitContext, account) + .result; } /** @@ -136,9 +143,13 @@ export class ERC20Simulator */ public allowance( owner: Either, - spender: Either + spender: Either, ): bigint { - return this.contract.impureCircuits.allowance(this.circuitContext, owner, spender).result; + return this.contract.impureCircuits.allowance( + this.circuitContext, + owner, + spender, + ).result; } /** @@ -148,13 +159,20 @@ export class ERC20Simulator * @param sender The simulated caller. * @returns As per the IERC20 spec, this MUST return true. */ - public transfer(to: Either, value: bigint, sender?: CoinPublicKey): boolean { - const res = this.contract.impureCircuits.transfer({ + public transfer( + to: Either, + value: bigint, + sender?: CoinPublicKey, + ): boolean { + const res = this.contract.impureCircuits.transfer( + { ...this.circuitContext, currentZswapLocalState: sender ? emptyZswapLocalState(sender) : this.circuitContext.currentZswapLocalState, - }, to, value + }, + to, + value, ); this.circuitContext = res.context; @@ -174,15 +192,18 @@ export class ERC20Simulator from: Either, to: Either, value: bigint, - sender?: CoinPublicKey + sender?: CoinPublicKey, ): boolean { - const res = this.contract.impureCircuits.transferFrom({ + const res = this.contract.impureCircuits.transferFrom( + { ...this.circuitContext, currentZswapLocalState: sender ? emptyZswapLocalState(sender) : this.circuitContext.currentZswapLocalState, - }, - from, to, value + }, + from, + to, + value, ); this.circuitContext = res.context; @@ -196,14 +217,20 @@ export class ERC20Simulator * @param sender The simulated caller. * @returns Returns a boolean value indicating whether the operation succeeded. */ - public approve(spender: Either, value: bigint, sender?: CoinPublicKey): boolean { - const res = this.contract.impureCircuits.approve({ + public approve( + spender: Either, + value: bigint, + sender?: CoinPublicKey, + ): boolean { + const res = this.contract.impureCircuits.approve( + { ...this.circuitContext, currentZswapLocalState: sender ? emptyZswapLocalState(sender) : this.circuitContext.currentZswapLocalState, - }, - spender, value + }, + spender, + value, ); this.circuitContext = res.context; @@ -226,9 +253,14 @@ export class ERC20Simulator public _approve( owner: Either, spender: Either, - value: bigint + value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._approve(this.circuitContext, owner, spender, value).context; + this.circuitContext = this.contract.impureCircuits._approve( + this.circuitContext, + owner, + spender, + value, + ).context; } /** @@ -244,7 +276,12 @@ export class ERC20Simulator to: Either, value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._transfer(this.circuitContext, from, to, value).context; + this.circuitContext = this.contract.impureCircuits._transfer( + this.circuitContext, + from, + to, + value, + ).context; } /** @@ -253,8 +290,15 @@ export class ERC20Simulator * @param account The recipient of tokens minted. * @param value The amount of tokens minted. */ - public _mint(account: Either, value: bigint) { - this.circuitContext = this.contract.impureCircuits._mint(this.circuitContext, account, value).context; + public _mint( + account: Either, + value: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._mint( + this.circuitContext, + account, + value, + ).context; } /** @@ -263,8 +307,15 @@ export class ERC20Simulator * @param account The target owner of tokens to burn. * @param value The amount of tokens to burn. */ - public _burn(account: Either, value: bigint) { - this.circuitContext = this.contract.impureCircuits._burn(this.circuitContext, account, value).context; + public _burn( + account: Either, + value: bigint, + ) { + this.circuitContext = this.contract.impureCircuits._burn( + this.circuitContext, + account, + value, + ).context; } /** @@ -277,9 +328,14 @@ export class ERC20Simulator public _update( from: Either, to: Either, - value: bigint + value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._update(this.circuitContext, from, to, value).context; + this.circuitContext = this.contract.impureCircuits._update( + this.circuitContext, + from, + to, + value, + ).context; } /** @@ -292,8 +348,13 @@ export class ERC20Simulator public _spendAllowance( owner: Either, spender: Either, - value: bigint + value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._spendAllowance(this.circuitContext, owner, spender, value).context; + this.circuitContext = this.contract.impureCircuits._spendAllowance( + this.circuitContext, + owner, + spender, + value, + ).context; } } diff --git a/contracts/erc20/src/test/utils/address.ts b/contracts/erc20/src/test/utils/address.ts index ef9a2842..3580e196 100644 --- a/contracts/erc20/src/test/utils/address.ts +++ b/contracts/erc20/src/test/utils/address.ts @@ -1,8 +1,11 @@ +import { + convert_bigint_to_Uint8Array, + encodeCoinPublicKey, +} from '@midnight-ntwrk/compact-runtime'; import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import * as Compact from '../../artifacts/MockERC20/contract/index.cjs'; -import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; +import type * as Compact from '../../artifacts/MockERC20/contract/index.cjs'; -const PREFIX_ADDRESS = "0200"; +const PREFIX_ADDRESS = '0200'; export const pad = (s: string, n: number): Uint8Array => { const encoder = new TextEncoder(); @@ -13,7 +16,7 @@ export const pad = (s: string, n: number): Uint8Array => { const paddedArray = new Uint8Array(n); paddedArray.set(utf8Bytes); return paddedArray; -} +}; /** * @description Generates ZswapCoinPublicKey from `str` for testing purposes. @@ -23,7 +26,7 @@ export const pad = (s: string, n: number): Uint8Array => { export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { const toHex = Buffer.from(str, 'ascii').toString('hex'); return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; -} +}; /** * @description Generates ContractAddress from `str` for testing purposes. @@ -35,7 +38,7 @@ export const encodeToAddress = (str: string): Compact.ContractAddress => { const toHex = Buffer.from(str, 'ascii').toString('hex'); const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); return { bytes: encodeContractAddress(fullAddress) }; -} +}; /** * @description Generates an Either object for ZswapCoinPublicKey for testing. @@ -47,9 +50,9 @@ export const createEitherTestUser = (str: string) => { return { is_left: true, left: encodeToPK(str), - right: encodeToAddress('') - } -} + right: encodeToAddress(''), + }; +}; /** * @description Generates an Either object for ContractAddress for testing. @@ -61,18 +64,18 @@ export const createEitherTestContractAddress = (str: string) => { return { is_left: false, left: encodeToPK(''), - right: encodeToAddress(str) - } -} + right: encodeToAddress(str), + }; +}; export const ZERO_KEY = { is_left: true, left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, - right: encodeToAddress('') -} + right: encodeToAddress(''), +}; export const ZERO_ADDRESS = { is_left: false, left: encodeToPK(''), - right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) } -} + right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, +}; diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 905c5d18..490074d0 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -14,7 +14,6 @@ } }, "scripts": { -<<<<<<< HEAD "compact": "compact-compiler", "build": "compact-builder && tsc", "test": "vitest run", @@ -26,14 +25,6 @@ }, "dependencies": { "@openzeppelin-midnight/compact": "workspace:^" -======= - "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", - "test": "NODE_OPTIONS=--experimental-vm-modules jest", - "prepack": "yarn build", - "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/{Initializable,Pausable,Utils}.compact ./dist", - "lint": "eslint src", - "typecheck": "tsc -p tsconfig.json --noEmit" ->>>>>>> b6f5215 (Add pausable (#22)) }, "devDependencies": { "@biomejs/biome": "1.9.4", @@ -42,4 +33,4 @@ "typescript": "^5.2.2", "vitest": "^3.1.3" } -} +} \ No newline at end of file diff --git a/contracts/utils/src/test/Initializable.test.ts b/contracts/utils/src/test/Initializable.test.ts index 19c29371..a3bb2eba 100644 --- a/contracts/utils/src/test/Initializable.test.ts +++ b/contracts/utils/src/test/Initializable.test.ts @@ -1,10 +1,5 @@ -<<<<<<< HEAD import { beforeEach, describe, expect, it } from 'vitest'; import { InitializableSimulator } from './simulators/InitializableSimulator.js'; -======= -import { it, describe, expect } from '@jest/globals'; -import { InitializableSimulator } from './simulators/InitializableSimulator'; ->>>>>>> b6f5215 (Add pausable (#22)) let initializable: InitializableSimulator; @@ -15,29 +10,20 @@ describe('Initializable', () => { it('should generate the initial ledger state deterministically', () => { const initializable2 = new InitializableSimulator(); -<<<<<<< HEAD expect(initializable.getCurrentPublicState()).toEqual( initializable2.getCurrentPublicState(), ); -======= - expect(initializable.getCurrentPublicState()).toEqual(initializable2.getCurrentPublicState()); ->>>>>>> b6f5215 (Add pausable (#22)) }); describe('initialize', () => { it('should not be initialized', () => { -<<<<<<< HEAD expect( initializable.getCurrentPublicState().initializable_IsInitialized, ).toEqual(false); -======= - expect(initializable.getCurrentPublicState().initializable_IsInitialized).toEqual(false); ->>>>>>> b6f5215 (Add pausable (#22)) }); it('should initialize', () => { initializable.initialize(); -<<<<<<< HEAD expect( initializable.getCurrentPublicState().initializable_IsInitialized, ).toEqual(true); @@ -49,17 +35,6 @@ describe('Initializable', () => { initializable.initialize(); initializable.initialize(); }).toThrow('Initializable: contract already initialized'); -======= - expect(initializable.getCurrentPublicState().initializable_IsInitialized).toEqual(true); - }); - }); - - it('should fail when re-initialized', () => { - expect(() => { - initializable.initialize(); - initializable.initialize(); - }).toThrow('Initializable: contract already initialized'); ->>>>>>> b6f5215 (Add pausable (#22)) }); describe('assertInitialized', () => { diff --git a/contracts/utils/src/test/simulators/InitializableSimulator.ts b/contracts/utils/src/test/simulators/InitializableSimulator.ts index 81a01d3a..c8e36cf7 100644 --- a/contracts/utils/src/test/simulators/InitializableSimulator.ts +++ b/contracts/utils/src/test/simulators/InitializableSimulator.ts @@ -29,8 +29,7 @@ import { InitializablePrivateState, InitializableWitnesses } from '../../witness * @template L - The ledger type, fixed to Contract.Ledger. */ export class InitializableSimulator - implements IContractSimulator -{ + implements IContractSimulator { /** @description The underlying contract instance managing contract logic. */ readonly contract: MockInitializable; diff --git a/contracts/utils/src/test/simulators/PausableSimulator.ts b/contracts/utils/src/test/simulators/PausableSimulator.ts index e80dcb96..f554822d 100644 --- a/contracts/utils/src/test/simulators/PausableSimulator.ts +++ b/contracts/utils/src/test/simulators/PausableSimulator.ts @@ -1,4 +1,3 @@ -<<<<<<< HEAD import { type CircuitContext, type ContractState, @@ -16,12 +15,6 @@ import { PausableWitnesses, } from '../../witnesses/PausableWitnesses.js'; import type { IContractSimulator } from '../types/test.js'; -======= -import { type CircuitContext, type ContractState, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; -import { Contract as MockPausable, type Ledger, ledger } from '../../artifacts/MockPausable/contract/index.cjs'; -import type { IContractSimulator } from '../types/test'; -import { PausablePrivateState, PausableWitnesses } from '../../witnesses/PausableWitnesses'; ->>>>>>> b6f5215 (Add pausable (#22)) /** * @description A simulator implementation of an utils contract for testing purposes. @@ -29,8 +22,7 @@ import { PausablePrivateState, PausableWitnesses } from '../../witnesses/Pausabl * @template L - The ledger type, fixed to Contract.Ledger. */ export class PausableSimulator - implements IContractSimulator -{ + implements IContractSimulator { /** @description The underlying contract instance managing contract logic. */ readonly contract: MockPausable; @@ -44,24 +36,13 @@ export class PausableSimulator * @description Initializes the mock contract. */ constructor() { -<<<<<<< HEAD this.contract = new MockPausable(PausableWitnesses); -======= - this.contract = new MockPausable( - PausableWitnesses, - ); ->>>>>>> b6f5215 (Add pausable (#22)) const { currentPrivateState, currentContractState, currentZswapLocalState, -<<<<<<< HEAD } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); -======= - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)) - ); ->>>>>>> b6f5215 (Add pausable (#22)) + this.circuitContext = { currentPrivateState, currentZswapLocalState, @@ -111,13 +92,7 @@ export class PausableSimulator * @returns None. */ public assertPaused() { -<<<<<<< HEAD - this.circuitContext = this.contract.impureCircuits.assertPaused( - this.circuitContext, - ).context; -======= this.circuitContext = this.contract.impureCircuits.assertPaused(this.circuitContext).context; ->>>>>>> b6f5215 (Add pausable (#22)) } /** @@ -125,13 +100,7 @@ export class PausableSimulator * @returns None. */ public assertNotPaused() { -<<<<<<< HEAD - this.circuitContext = this.contract.impureCircuits.assertNotPaused( - this.circuitContext, - ).context; -======= this.circuitContext = this.contract.impureCircuits.assertNotPaused(this.circuitContext).context; ->>>>>>> b6f5215 (Add pausable (#22)) } /** @@ -139,13 +108,7 @@ export class PausableSimulator * @returns None. */ public pause() { -<<<<<<< HEAD - this.circuitContext = this.contract.impureCircuits.pause( - this.circuitContext, - ).context; -======= this.circuitContext = this.contract.impureCircuits.pause(this.circuitContext).context; ->>>>>>> b6f5215 (Add pausable (#22)) } /** @@ -153,12 +116,6 @@ export class PausableSimulator * @returns None. */ public unpause() { -<<<<<<< HEAD - this.circuitContext = this.contract.impureCircuits.unpause( - this.circuitContext, - ).context; -======= this.circuitContext = this.contract.impureCircuits.unpause(this.circuitContext).context; ->>>>>>> b6f5215 (Add pausable (#22)) } } diff --git a/contracts/utils/src/test/simulators/UtilsSimulator.ts b/contracts/utils/src/test/simulators/UtilsSimulator.ts index 6de40832..3a564524 100644 --- a/contracts/utils/src/test/simulators/UtilsSimulator.ts +++ b/contracts/utils/src/test/simulators/UtilsSimulator.ts @@ -22,11 +22,13 @@ import type { IContractSimulator } from '../types/test.js'; ======= type Ledger, Contract as MockUtils, + type ZswapCoinPublicKey, ledger, - Either, - ZswapCoinPublicKey, - ContractAddress, } from '../../artifacts/MockUtils/contract/index.cjs'; // Combined imports +import { + type UtilsPrivateState, + UtilsWitnesses, +} from '../../witnesses/UtilsWitnesses'; import type { IContractSimulator } from '../types/test'; import { UtilsPrivateState, UtilsWitnesses } from '../../witnesses/UtilsWitnesses'; >>>>>>> b6f5215 (Add pausable (#22)) diff --git a/contracts/utils/src/test/types/test.ts b/contracts/utils/src/test/types/test.ts index 10fb6c98..7a909543 100644 --- a/contracts/utils/src/test/types/test.ts +++ b/contracts/utils/src/test/types/test.ts @@ -1,4 +1,7 @@ -import type { CircuitContext, ContractState } from '@midnight-ntwrk/compact-runtime'; +import type { + CircuitContext, + ContractState, +} from '@midnight-ntwrk/compact-runtime'; /** * Generic interface for mock contract implementations. diff --git a/contracts/utils/src/test/utils/address.ts b/contracts/utils/src/test/utils/address.ts index 26466ab5..f288ae82 100644 --- a/contracts/utils/src/test/utils/address.ts +++ b/contracts/utils/src/test/utils/address.ts @@ -3,8 +3,7 @@ import { encodeCoinPublicKey, } from '@midnight-ntwrk/compact-runtime'; import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import * as Compact from '../../artifacts/MockUtils/contract/index.cjs'; -import { convert_bigint_to_Uint8Array, encodeCoinPublicKey } from '@midnight-ntwrk/compact-runtime'; +import type * as Compact from '../../artifacts/MockUtils/contract/index.cjs'; const PREFIX_ADDRESS = '0200'; diff --git a/contracts/utils/src/test/utils/index.ts b/contracts/utils/src/test/utils/index.ts new file mode 100644 index 00000000..b8e9585d --- /dev/null +++ b/contracts/utils/src/test/utils/index.ts @@ -0,0 +1,10 @@ +export { useCircuitContext as circuitContext } from './test'; +export { + pad, + encodeToPK, + encodeToAddress, + createEitherTestUser, + createEitherTestContractAddress, + ZERO_KEY, + ZERO_ADDRESS, +} from './address'; diff --git a/contracts/utils/src/test/utils/test.ts b/contracts/utils/src/test/utils/test.ts index a8840104..d467e572 100644 --- a/contracts/utils/src/test/utils/test.ts +++ b/contracts/utils/src/test/utils/test.ts @@ -1,10 +1,10 @@ import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - QueryContext, - emptyZswapLocalState, + type CircuitContext, + type CoinPublicKey, + type ContractAddress, + type ContractState, + QueryContext, + emptyZswapLocalState, } from '@midnight-ntwrk/compact-runtime'; import type { IContractSimulator } from '../types/test'; @@ -50,10 +50,11 @@ export function useCircuitContext

( * @returns A new `CircuitContext` with the sender and updated context values. * @todo TODO: Move this utility to a generic package for broader reuse across contracts. */ -export function useCircuitContextSender>( - contract: C, - sender: CoinPublicKey, -): CircuitContext

{ +export function useCircuitContextSender< + P, + L, + C extends IContractSimulator, +>(contract: C, sender: CoinPublicKey): CircuitContext

{ const currentPrivateState = contract.getCurrentPrivateState(); const originalState = contract.getCurrentContractState(); const contractAddress = contract.contractAddress; diff --git a/turbo.json b/turbo.json index d19f046b..d00de0d1 100644 --- a/turbo.json +++ b/turbo.json @@ -2,20 +2,37 @@ "$schema": "https://turbo.build/schema.json", "tasks": { "compact": { - "dependsOn": ["^build"], - "env": ["COMPACT_HOME"], - "inputs": ["src/**/*.compact"], + "dependsOn": [ + "^build" + ], + "env": [ + "COMPACT_HOME" + ], + "inputs": [ + "src/**/*.compact" + ], "outputLogs": "new-only", - "outputs": ["src/artifacts/**", "src/gen/**", "gen/**"] + "outputs": [ + "src/artifacts/**", + "src/gen/**", + "gen/**" + ] }, "test": { - "dependsOn": ["^build", "compact"], + "dependsOn": [ + "^build", + "compact" + ], "outputs": [], "cache": false }, "build": { - "dependsOn": ["^build"], - "env": ["COMPACT_HOME"], + "dependsOn": [ + "^build" + ], + "env": [ + "COMPACT_HOME" + ], "inputs": [ "src/**/*.ts", "!src/**/*.test.ts", @@ -24,10 +41,14 @@ "tsconfig.build.json", ".env" ], - "outputs": ["dist/**"] + "outputs": [ + "dist/**" + ] }, "types": { - "dependsOn": ["compact"], + "dependsOn": [ + "compact" + ], "outputs": [], "cache": false }, @@ -49,4 +70,4 @@ "cache": false } } -} +} \ No newline at end of file From 7195d018961e51688539067fd0da0048ea09fa44 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 6 May 2025 20:32:14 -0400 Subject: [PATCH 270/282] Add security doc (#42) * add security section and doc * fix email * Update README.md Co-authored-by: Iskander <0xisk@proton.me> * fix bare url --------- Co-authored-by: Iskander <0xisk@proton.me> --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index 68902d38..5985dd0e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,4 +4,4 @@ Security vulnerabilities should be disclosed to the project maintainers by email ## Legal -Blockchain is a nascent technology and carries a high level of risk and uncertainty. OpenZeppelin makes certain software available under open source licenses, which disclaim all warranties in relation to the project and which limits the liability of OpenZeppelin. Subject to any particular licensing terms, your use of the project is governed by the terms found at [www.openzeppelin.com/tos](https://www.openzeppelin.com/tos) (the "Terms"). As set out in the Terms, you are solely responsible for any use of the project and you assume all risks associated with any such use. This Security Policy in no way evidences or represents an ongoing duty by any contributor, including OpenZeppelin, to correct any issues or vulnerabilities or alert you to all or any of the risks of utilizing the project. \ No newline at end of file +Blockchain is a nascent technology and carries a high level of risk and uncertainty. OpenZeppelin makes certain software available under open source licenses, which disclaim all warranties in relation to the project and which limits the liability of OpenZeppelin. Subject to any particular licensing terms, your use of the project is governed by the terms found at [www.openzeppelin.com/tos](https://www.openzeppelin.com/tos) (the "Terms"). As set out in the Terms, you are solely responsible for any use of the project and you assume all risks associated with any such use. This Security Policy in no way evidences or represents an ongoing duty by any contributor, including OpenZeppelin, to correct any issues or vulnerabilities or alert you to all or any of the risks of utilizing the project. From 94bdfbaeb73d178707254ef1d8136ac2812cdfd0 Mon Sep 17 00:00:00 2001 From: Iskander Date: Fri, 9 May 2025 04:23:45 +0200 Subject: [PATCH 271/282] chore: add code owners (#53) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 292a22bb..47dbba63 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -13,4 +13,4 @@ # Global: -* @OpenZeppelin/contracts-midnight-maintainers +* @OpenZeppelin/contracts-midnight-maintainers From cafc086dd952cc9f76129712e4b55c4b708cbd29 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Wed, 14 May 2025 14:34:00 -0400 Subject: [PATCH 272/282] Improve compact scripts (#41) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bump midnight-js * remove unused deps * remove eslint and prettier, add biome * run fmt * run lint * organize imports * remove dev deps from contracts/ * remove unused deps * update turbo and scripts * add clean script * add clean script * clean up test config * remove jest reporters * bump turbo to 2.5 * bump turbo * fix package names * set up compact compiler and builder * update scripts * update yarn.lock * update readme * fix fmt * fix fmt * remove lingering file * update biome, fix fmt * add requirements in dev section * add devdeps to contracts packages * simplify workspace * remove unnecessary button rule * fix fmt * remove useExhaustiveDeps rule * Uses recommended compiler options for Node 22 and TypeScript 5.8 * Update compact/src/Builder.ts Co-authored-by: Iskander <0xisk@proton.me> * remove author * Apply suggestions from code review Co-authored-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> * Update biome.json Co-authored-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> * fix correctness and a11y * remove implicit trailingCommas and indentWidth * add stderr discard notice * change dirent.path to parentPath * add getCompactFiles method * fix lint * Improves type safety via custom error type * output will never be null * remove redundant check * Colocate error types into their own file * Adds type guard to `executeStep` * Add type guard to `compileFile` * Fix fmt * update printOutput function signature --------- Co-authored-by: Emanuel Solis Co-authored-by: Iskander <0xisk@proton.me> Co-authored-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- README.md | 6 ++++ biome.json | 2 +- compact/package.json | 2 +- compact/tsconfig.json | 48 +++++++++++++------------ contracts/erc20/package.json | 13 +++++-- contracts/erc20/src/test/erc20.test.ts | 3 +- contracts/erc20/src/test/utils/index.ts | 2 -- contracts/utils/src/test/utils/index.ts | 10 ------ package.json | 2 +- yarn.lock | 21 +++++++++++ 10 files changed, 66 insertions(+), 43 deletions(-) delete mode 100644 contracts/erc20/src/test/utils/index.ts delete mode 100644 contracts/utils/src/test/utils/index.ts diff --git a/README.md b/README.md index ec3108b3..8cf7523a 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,12 @@ Usage: compactc.bin ... > - [turbo](https://turborepo.com/docs/getting-started/installation) > - [compact](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) +> ### Requirements +> +> - [node](https://nodejs.org/) +> - [yarn](https://yarnpkg.com/getting-started/install) +> - [compact](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) + Clone the repository: ```bash diff --git a/biome.json b/biome.json index 10c26977..4f3ef27a 100644 --- a/biome.json +++ b/biome.json @@ -28,7 +28,7 @@ "organizeImports": { "enabled": true }, - "linter": { +"linter": { "enabled": true, "rules": { "recommended": true, diff --git a/compact/package.json b/compact/package.json index 786f6b0c..29b62262 100644 --- a/compact/package.json +++ b/compact/package.json @@ -37,4 +37,4 @@ "log-symbols": "^7.0.0", "ora": "^8.2.0" } -} +} \ No newline at end of file diff --git a/compact/tsconfig.json b/compact/tsconfig.json index 145be791..55676612 100644 --- a/compact/tsconfig.json +++ b/compact/tsconfig.json @@ -1,25 +1,27 @@ { - "compilerOptions": { - "outDir": "dist", - "rootDir": "src", - "declaration": true, - "lib": ["es2022"], - "module": "nodenext", - "target": "es2022", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "moduleResolution": "nodenext", - "sourceMap": true, - "rewriteRelativeImportExtensions": true, - "erasableSyntaxOnly": true, - "verbatimModuleSyntax": true - }, - "include": [ - "src/**/*" + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "declaration": true, + "lib": [ + "es2022" ], - "exclude": [ - "node_modules", - "dist" - ] -} + "module": "nodenext", + "target": "es2022", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "moduleResolution": "nodenext", + "sourceMap": true, + "rewriteRelativeImportExtensions": true, + "erasableSyntaxOnly": true, + "verbatimModuleSyntax": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/contracts/erc20/package.json b/contracts/erc20/package.json index c64d5517..bb471653 100644 --- a/contracts/erc20/package.json +++ b/contracts/erc20/package.json @@ -13,9 +13,9 @@ } }, "scripts": { - "compact": "find src -name '*.compact' -exec sh -c 'run-compactc \"{}\" \"src/artifacts/$(basename \"{}\" .compact)\"' \\;", + "compact": "npx compact-compiler", + "build": "npx compact-builder && tsc", "test": "NODE_OPTIONS=--experimental-vm-modules jest", - "build": "rm -rf dist && tsc --project tsconfig.build.json && cp -Rf ./src/artifacts ./dist/artifacts && cp ./src/ERC20.compact ./dist", "types": "tsc -p tsconfig.json --noEmit", "fmt": "biome format", "fmt:fix": "biome format --write", @@ -24,6 +24,13 @@ "clean": "git clean -fXd" }, "dependencies": { - "@openzeppelin-midnight/utils": "workspace:^" + "@openzeppelin-midnight/compact": "workspace:^" + }, + "devDependencies": { + "@biomejs/biome": "1.9.4", + "@types/jest": "^29.5.6", + "@types/node": "^18.18.6", + "jest": "^29.7.0", + "typescript": "^5.2.2" } } diff --git a/contracts/erc20/src/test/erc20.test.ts b/contracts/erc20/src/test/erc20.test.ts index 8e9a4596..414b3ea2 100644 --- a/contracts/erc20/src/test/erc20.test.ts +++ b/contracts/erc20/src/test/erc20.test.ts @@ -1,7 +1,7 @@ import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; import { ERC20Simulator } from './simulators/ERC20Simulator'; import type { MaybeString } from './types/string'; -import * as utils from './utils'; +import * as utils from './utils/address'; const NO_STRING: MaybeString = { is_some: false, @@ -35,7 +35,6 @@ const Z_OWNER = utils.createEitherTestUser('OWNER'); const Z_RECIPIENT = utils.createEitherTestUser('RECIPIENT'); const Z_SPENDER = utils.createEitherTestUser('SPENDER'); const Z_OTHER = utils.createEitherTestUser('OTHER'); -const SOME_CONTRACT = utils.createEitherTestContractAddress('SOME_CONTRACT'); let token: ERC20Simulator; let caller: CoinPublicKey; diff --git a/contracts/erc20/src/test/utils/index.ts b/contracts/erc20/src/test/utils/index.ts deleted file mode 100644 index 731fe1ec..00000000 --- a/contracts/erc20/src/test/utils/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { useCircuitContext as circuitContext } from './test'; -export * from './address'; diff --git a/contracts/utils/src/test/utils/index.ts b/contracts/utils/src/test/utils/index.ts deleted file mode 100644 index b8e9585d..00000000 --- a/contracts/utils/src/test/utils/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -export { useCircuitContext as circuitContext } from './test'; -export { - pad, - encodeToPK, - encodeToAddress, - createEitherTestUser, - createEitherTestContractAddress, - ZERO_KEY, - ZERO_ADDRESS, -} from './address'; diff --git a/package.json b/package.json index da56058b..c6ee2f02 100644 --- a/package.json +++ b/package.json @@ -34,4 +34,4 @@ "typescript": "^5.2.2", "vitest": "^3.1.3" } -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 58e73f6f..bd62773d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1073,6 +1073,13 @@ __metadata: languageName: node linkType: hard +"emoji-regex@npm:^10.3.0": + version: 10.4.0 + resolution: "emoji-regex@npm:10.4.0" + checksum: 10/76bb92c5bcf0b6980d37e535156231e4a9d0aa6ab3b9f5eabf7690231d5aa5d5b8e516f36e6804cbdd0f1c23dfef2a60c40ab7bb8aedd890584281a565b97c50 + languageName: node + linkType: hard + "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -1480,6 +1487,20 @@ __metadata: languageName: node linkType: hard +"is-unicode-supported@npm:^1.3.0": + version: 1.3.0 + resolution: "is-unicode-supported@npm:1.3.0" + checksum: 10/20a1fc161afafaf49243551a5ac33b6c4cf0bbcce369fcd8f2951fbdd000c30698ce320de3ee6830497310a8f41880f8066d440aa3eb0a853e2aa4836dd89abc + languageName: node + linkType: hard + +"is-unicode-supported@npm:^2.0.0": + version: 2.1.0 + resolution: "is-unicode-supported@npm:2.1.0" + checksum: 10/f254e3da6b0ab1a57a94f7273a7798dd35d1d45b227759f600d0fa9d5649f9c07fa8d3c8a6360b0e376adf916d151ec24fc9a50c5295c58bae7ca54a76a063f9 + languageName: node + linkType: hard + "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" From 8875d9e54d1be31993d08c3f729cbacc796e2e12 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Mon, 19 May 2025 17:47:05 -0400 Subject: [PATCH 273/282] Support compact 0.23.0, migrate to vitest (#68) * migrate to vitest, bump compact-runtime * use vitest run, remove vitest ui dep * add vitest imports for testing * remove vitest ui * bump compact-runtime to 0.8.1 * set vitest reporters to verbose * fix fmt * fix lint * remove unused dep --- contracts/erc20/jest.config.ts | 16 ------------ contracts/erc20/package.json | 8 +++--- contracts/erc20/src/ERC20.compact | 2 +- contracts/erc20/src/test/erc20.test.ts | 1 + .../erc20/src/test/mocks/MockERC20.compact | 2 +- contracts/erc20/vitest.config.ts | 10 +++++++ contracts/utils/src/Initializable.compact | 4 --- yarn.lock | 26 ++++--------------- 8 files changed, 22 insertions(+), 47 deletions(-) delete mode 100644 contracts/erc20/jest.config.ts create mode 100644 contracts/erc20/vitest.config.ts diff --git a/contracts/erc20/jest.config.ts b/contracts/erc20/jest.config.ts deleted file mode 100644 index bde5bde1..00000000 --- a/contracts/erc20/jest.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { Config } from '@jest/types'; - -const config: Config.InitialOptions = { - preset: 'ts-jest/presets/default-esm', - testEnvironment: 'node', - verbose: true, - roots: [''], - modulePaths: [''], - passWithNoTests: false, - testMatch: ['**/*.test.ts'], - extensionsToTreatAsEsm: ['.ts'], - collectCoverage: false, - resolver: '/js-resolver.cjs', -}; - -export default config; diff --git a/contracts/erc20/package.json b/contracts/erc20/package.json index bb471653..251de568 100644 --- a/contracts/erc20/package.json +++ b/contracts/erc20/package.json @@ -15,7 +15,7 @@ "scripts": { "compact": "npx compact-compiler", "build": "npx compact-builder && tsc", - "test": "NODE_OPTIONS=--experimental-vm-modules jest", + "test": "vitest run", "types": "tsc -p tsconfig.json --noEmit", "fmt": "biome format", "fmt:fix": "biome format --write", @@ -28,9 +28,9 @@ }, "devDependencies": { "@biomejs/biome": "1.9.4", - "@types/jest": "^29.5.6", "@types/node": "^18.18.6", - "jest": "^29.7.0", - "typescript": "^5.2.2" + "ts-node": "^10.9.2", + "typescript": "^5.2.2", + "vitest": "^3.1.3" } } diff --git a/contracts/erc20/src/ERC20.compact b/contracts/erc20/src/ERC20.compact index 31ca0059..da0c63b6 100644 --- a/contracts/erc20/src/ERC20.compact +++ b/contracts/erc20/src/ERC20.compact @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma language_version >= 0.14.0; +pragma language_version >= 0.15.0; /** * @module ERC20 diff --git a/contracts/erc20/src/test/erc20.test.ts b/contracts/erc20/src/test/erc20.test.ts index 414b3ea2..90d95413 100644 --- a/contracts/erc20/src/test/erc20.test.ts +++ b/contracts/erc20/src/test/erc20.test.ts @@ -1,4 +1,5 @@ import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { ERC20Simulator } from './simulators/ERC20Simulator'; import type { MaybeString } from './types/string'; import * as utils from './utils/address'; diff --git a/contracts/erc20/src/test/mocks/MockERC20.compact b/contracts/erc20/src/test/mocks/MockERC20.compact index e5e8a9da..2d2084f1 100644 --- a/contracts/erc20/src/test/mocks/MockERC20.compact +++ b/contracts/erc20/src/test/mocks/MockERC20.compact @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma language_version >= 0.14.0; +pragma language_version >= 0.15.0; import CompactStandardLibrary; diff --git a/contracts/erc20/vitest.config.ts b/contracts/erc20/vitest.config.ts new file mode 100644 index 00000000..785b792e --- /dev/null +++ b/contracts/erc20/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['src/test/**/*.test.ts'], + reporters: 'verbose', + }, +}); diff --git a/contracts/utils/src/Initializable.compact b/contracts/utils/src/Initializable.compact index 3e55ceea..99a2c0e1 100644 --- a/contracts/utils/src/Initializable.compact +++ b/contracts/utils/src/Initializable.compact @@ -1,9 +1,5 @@ // SPDX-License-Identifier: MIT -<<<<<<< HEAD pragma language_version >= 0.15.0; -======= -pragma language_version >= 0.14.0; ->>>>>>> b6f5215 (Add pausable (#22)) /** * @module Initializable diff --git a/yarn.lock b/yarn.lock index bd62773d..bcd0698a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -804,7 +804,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": +"ansi-styles@npm:^4.0.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: @@ -1883,13 +1883,6 @@ __metadata: languageName: node linkType: hard -"p-try@npm:^2.0.0": - version: 2.2.0 - resolution: "p-try@npm:2.2.0" - checksum: 10/f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae - languageName: node - linkType: hard - "package-json-from-dist@npm:^1.0.0": version: 1.0.1 resolution: "package-json-from-dist@npm:1.0.1" @@ -2180,13 +2173,6 @@ __metadata: languageName: node linkType: hard -"sprintf-js@npm:~1.0.2": - version: 1.0.3 - resolution: "sprintf-js@npm:1.0.3" - checksum: 10/c34828732ab8509c2741e5fd1af6b767c3daf2c642f267788f933a65b1614943c282e74c4284f4fa749c264b18ee016a0d37a3e5b73aee446da46277d3a85daa - languageName: node - linkType: hard - "ssri@npm:^12.0.0": version: 12.0.0 resolution: "ssri@npm:12.0.0" @@ -2345,12 +2331,10 @@ __metadata: languageName: node linkType: hard -"to-regex-range@npm:^5.0.1": - version: 5.0.1 - resolution: "to-regex-range@npm:5.0.1" - dependencies: - is-number: "npm:^7.0.0" - checksum: 10/10dda13571e1f5ad37546827e9b6d4252d2e0bc176c24a101252153ef435d83696e2557fe128c4678e4e78f5f01e83711c703eef9814eb12dab028580d45980a +"tinyrainbow@npm:^2.0.0": + version: 2.0.0 + resolution: "tinyrainbow@npm:2.0.0" + checksum: 10/94d4e16246972614a5601eeb169ba94f1d49752426312d3cf8cc4f2cc663a2e354ffc653aa4de4eebccbf9eeebdd0caef52d1150271fdfde65d7ae7f3dcb9eb5 languageName: node linkType: hard From eb4ebfd30f1a1b2b724bfd34f4ed9332f12f510b Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 27 May 2025 18:01:36 -0400 Subject: [PATCH 274/282] Set private prop to true in package.json (#84) --- contracts/erc20/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/erc20/package.json b/contracts/erc20/package.json index 251de568..a75d5df8 100644 --- a/contracts/erc20/package.json +++ b/contracts/erc20/package.json @@ -1,5 +1,6 @@ { "name": "@openzeppelin-midnight/erc20", + "private": true, "type": "module", "main": "dist/index.js", "module": "dist/index.js", From 8b2d43d42fe3a3c6271488b8b2caca77541653b7 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 27 May 2025 18:04:39 -0400 Subject: [PATCH 275/282] Set up antora and overview page (#83) --- docs/package.json | 2 +- yarn.lock | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/package.json b/docs/package.json index 02410b35..2b54a42a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -12,4 +12,4 @@ "devDependencies": { "@openzeppelin/docs-utils": "^0.1.5" } -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index bcd0698a..3b7f56bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -804,7 +804,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^4.0.0": +"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: @@ -1883,6 +1883,13 @@ __metadata: languageName: node linkType: hard +"p-try@npm:^2.0.0": + version: 2.2.0 + resolution: "p-try@npm:2.2.0" + checksum: 10/f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae + languageName: node + linkType: hard + "package-json-from-dist@npm:^1.0.0": version: 1.0.1 resolution: "package-json-from-dist@npm:1.0.1" @@ -2173,6 +2180,13 @@ __metadata: languageName: node linkType: hard +"sprintf-js@npm:~1.0.2": + version: 1.0.3 + resolution: "sprintf-js@npm:1.0.3" + checksum: 10/c34828732ab8509c2741e5fd1af6b767c3daf2c642f267788f933a65b1614943c282e74c4284f4fa749c264b18ee016a0d37a3e5b73aee446da46277d3a85daa + languageName: node + linkType: hard + "ssri@npm:^12.0.0": version: 12.0.0 resolution: "ssri@npm:12.0.0" From 828fcf40f64008098cb8a96c07cc449a2bd4d051 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 27 May 2025 18:06:08 -0400 Subject: [PATCH 276/282] Improve readme (#80) --- README.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8cf7523a..6793a155 100644 --- a/README.md +++ b/README.md @@ -31,11 +31,19 @@ Usage: compactc.bin ... > - [turbo](https://turborepo.com/docs/getting-started/installation) > - [compact](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) -> ### Requirements -> -> - [node](https://nodejs.org/) -> - [yarn](https://yarnpkg.com/getting-started/install) -> - [compact](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) +Make sure you have [nvm](https://github.com/nvm-sh/nvm) and [yarn](https://yarnpkg.com/getting-started/install) installed on your machine. + +Follow Midnight's [compact installation guide](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) and confirm that `compactc` is in the `PATH` env variable. + +```bash +$ compactc + +Compactc version: 0.23.0 +Usage: compactc.bin ... + --help displays detailed usage information +``` + +## Set up the project Clone the repository: From 0c99b1ab277a7f7dda953df11e331f5c4d317264 Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Fri, 6 Jun 2025 13:02:01 -0400 Subject: [PATCH 277/282] Add extensibility section (#86) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Iskander <0xisk@proton.me> Co-authored-by: Iskander Co-authored-by: Emanuel Solis Co-authored-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 6793a155..1043c6cb 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,12 @@ Usage: compactc.bin ... ## Set up the project +> ### Requirements +> +> - [node](https://nodejs.org/) +> - [yarn](https://yarnpkg.com/getting-started/install) +> - [compact](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) + Clone the repository: ```bash From 7d6f3e9027d0c263424aeff9d9d67111c742ade2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Wed, 18 Jun 2025 01:09:45 -0400 Subject: [PATCH 278/282] Adds CI Tests, Lints, Compile, Build (#113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> Co-authored-by: Andrew Fleming --- README.md | 1 + biome.json | 2 +- contracts/erc20/js-resolver.cjs | 20 -------------------- contracts/erc20/package.json | 11 +++-------- package.json | 6 +----- yarn.lock | 2 -- 6 files changed, 6 insertions(+), 36 deletions(-) delete mode 100644 contracts/erc20/js-resolver.cjs diff --git a/README.md b/README.md index 1043c6cb..b6c8ea06 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Usage: compactc.bin ... > > - [node](https://nodejs.org/) > - [yarn](https://yarnpkg.com/getting-started/install) +> - [turbo](https://turborepo.com/docs/getting-started/installation) > - [compact](https://docs.midnight.network/develop/tutorial/building/#midnight-compact-compiler) Clone the repository: diff --git a/biome.json b/biome.json index 4f3ef27a..10c26977 100644 --- a/biome.json +++ b/biome.json @@ -28,7 +28,7 @@ "organizeImports": { "enabled": true }, -"linter": { + "linter": { "enabled": true, "rules": { "recommended": true, diff --git a/contracts/erc20/js-resolver.cjs b/contracts/erc20/js-resolver.cjs deleted file mode 100644 index 19b6f50c..00000000 --- a/contracts/erc20/js-resolver.cjs +++ /dev/null @@ -1,20 +0,0 @@ -const jsResolver = (path, options) => { - const jsExtRegex = /\.js$/i; - const resolver = options.defaultResolver; - if ( - jsExtRegex.test(path) && - !options.basedir.includes('node_modules') && - !path.includes('node_modules') - ) { - const newPath = path.replace(jsExtRegex, '.ts'); - try { - return resolver(newPath, options); - } catch { - // use default resolver - } - } - - return resolver(path, options); -}; - -module.exports = jsResolver; diff --git a/contracts/erc20/package.json b/contracts/erc20/package.json index a75d5df8..1180a033 100644 --- a/contracts/erc20/package.json +++ b/contracts/erc20/package.json @@ -14,22 +14,17 @@ } }, "scripts": { - "compact": "npx compact-compiler", - "build": "npx compact-builder && tsc", + "compact": "compact-compiler", + "build": "compact-builder && tsc", "test": "vitest run", "types": "tsc -p tsconfig.json --noEmit", - "fmt": "biome format", - "fmt:fix": "biome format --write", - "lint": "biome lint", - "lint:fix": "biome check --write", "clean": "git clean -fXd" }, "dependencies": { "@openzeppelin-midnight/compact": "workspace:^" }, "devDependencies": { - "@biomejs/biome": "1.9.4", - "@types/node": "^18.18.6", + "@types/node": "22.14.0", "ts-node": "^10.9.2", "typescript": "^5.2.2", "vitest": "^3.1.3" diff --git a/package.json b/package.json index c6ee2f02..6d2b8dac 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,7 @@ "description": "Secure Smart Contract library for Midnight", "private": true, "packageManager": "yarn@4.1.0", - "workspaces": [ - "compact/", - "contracts/*/", - "docs/" - ], + "workspaces": ["compact/", "contracts/*/", "docs/"], "scripts": { "docs": "npx turbo run docs --filter=docs", "docs:watch": "npx turbo run docs:watch --filter=docs", diff --git a/yarn.lock b/yarn.lock index 3b7f56bd..b0301cf4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -420,7 +420,6 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken" dependencies: - "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:22.14.0" ts-node: "npm:^10.9.2" @@ -433,7 +432,6 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" dependencies: - "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:22.14.0" ts-node: "npm:^10.9.2" From 52a285d6b346a05275728db14c1b55a50b689cbd Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Mon, 23 Jun 2025 16:39:08 -0500 Subject: [PATCH 279/282] Fix fmt issue (#143) --- package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 6d2b8dac..c6ee2f02 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,11 @@ "description": "Secure Smart Contract library for Midnight", "private": true, "packageManager": "yarn@4.1.0", - "workspaces": ["compact/", "contracts/*/", "docs/"], + "workspaces": [ + "compact/", + "contracts/*/", + "docs/" + ], "scripts": { "docs": "npx turbo run docs --filter=docs", "docs:watch": "npx turbo run docs:watch --filter=docs", From c248397452b91571e62982298666515efcb7877c Mon Sep 17 00:00:00 2001 From: Andrew Fleming Date: Tue, 24 Jun 2025 22:55:39 -0500 Subject: [PATCH 280/282] Update fungible token (#125) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andrew Fleming Co-authored-by: Iskander Co-authored-by: ⟣ €₥ℵ∪ℓ ⟢ <34749913+emnul@users.noreply.github.com> --- contracts/erc20/package.json | 32 -- contracts/erc20/src/ERC20.compact | 328 ------------ contracts/erc20/src/test/erc20.test.ts | 493 ------------------ .../erc20/src/test/mocks/MockERC20.compact | 106 ---- .../src/test/simulators/ERC20Simulator.ts | 360 ------------- contracts/erc20/src/test/types/test.ts | 26 - contracts/erc20/src/test/utils/address.ts | 81 --- contracts/erc20/src/test/utils/test.ts | 72 --- .../erc20/src/witnesses/ERC20Witnesses.ts | 3 - contracts/erc20/tsconfig.build.json | 5 - contracts/erc20/tsconfig.json | 21 - contracts/erc20/vitest.config.ts | 10 - contracts/fungibleToken/package.json | 2 +- .../fungibleToken/src/FungibleToken.compact | 1 - .../test/simulators/FungibleTokenSimulator.ts | 3 +- .../fungibleToken/src/test/utils/test.ts | 1 + contracts/fungibleToken/tsconfig.json | 8 +- .../utils/src/test/mocks/MockUtils.compact | 15 + .../src/test/simulators/UtilsSimulator.ts | 36 +- contracts/utils/src/test/utils.test.ts | 48 ++ yarn.lock | 7 + 21 files changed, 81 insertions(+), 1577 deletions(-) delete mode 100644 contracts/erc20/package.json delete mode 100644 contracts/erc20/src/ERC20.compact delete mode 100644 contracts/erc20/src/test/erc20.test.ts delete mode 100644 contracts/erc20/src/test/mocks/MockERC20.compact delete mode 100644 contracts/erc20/src/test/simulators/ERC20Simulator.ts delete mode 100644 contracts/erc20/src/test/types/test.ts delete mode 100644 contracts/erc20/src/test/utils/address.ts delete mode 100644 contracts/erc20/src/test/utils/test.ts delete mode 100644 contracts/erc20/src/witnesses/ERC20Witnesses.ts delete mode 100644 contracts/erc20/tsconfig.build.json delete mode 100644 contracts/erc20/tsconfig.json delete mode 100644 contracts/erc20/vitest.config.ts diff --git a/contracts/erc20/package.json b/contracts/erc20/package.json deleted file mode 100644 index 1180a033..00000000 --- a/contracts/erc20/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "@openzeppelin-midnight/erc20", - "private": true, - "type": "module", - "main": "dist/index.js", - "module": "dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "require": "./dist/index.js", - "import": "./dist/index.js", - "default": "./dist/index.js" - } - }, - "scripts": { - "compact": "compact-compiler", - "build": "compact-builder && tsc", - "test": "vitest run", - "types": "tsc -p tsconfig.json --noEmit", - "clean": "git clean -fXd" - }, - "dependencies": { - "@openzeppelin-midnight/compact": "workspace:^" - }, - "devDependencies": { - "@types/node": "22.14.0", - "ts-node": "^10.9.2", - "typescript": "^5.2.2", - "vitest": "^3.1.3" - } -} diff --git a/contracts/erc20/src/ERC20.compact b/contracts/erc20/src/ERC20.compact deleted file mode 100644 index da0c63b6..00000000 --- a/contracts/erc20/src/ERC20.compact +++ /dev/null @@ -1,328 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.15.0; - -/** - * @module ERC20 - * @description An unshielded ERC20 library. - * - * @notice One notable difference regarding this implementation and the EIP20 spec - * consists of the token size. Uint<128> is used as the token size because Uint<256> - * cannot be supported. - * This is due to encoding limits on the midnight circuit backend: - * https://github.com/midnightntwrk/compactc/issues/929 - * - * @notice Further discussion and consideration required: - * - * - Consider changing the underscore in the internal methods to `unsafe` or - * adopting dot notation for prefixing imports. - * - Revise logic once contract-to-contract interactions are available on midnight. - * - Consider implementing an introspection mechanism for transfers to contracts. - * - Standardize which zero address to use (`ZswapCoinPublicKey` or `ContractAddress`). - */ -module ERC20 { - import CompactStandardLibrary; - import "../../node_modules/@openzeppelin-midnight/utils/src/Utils" prefix Utils_; - - /// Public state - export sealed ledger _name: Maybe>; - export sealed ledger _symbol: Maybe>; - export sealed ledger _decimals: Uint<8>; - export ledger _totalSupply: Uint<128>; - export ledger _balances: Map, Uint<128>>; - export ledger _allowances: Map, Map, Uint<128>>>; - - /** - * @description Initializes the contract by setting the name, symbol, and decimals. - * @dev This MUST be called in the implementing contract's constructor. Failure to do so - * can lead to an irreparable contract. - * - * @param name_ - The name of the token. - * @param symbol_ - The symbol of the token. - * @param decimals_ - The number of decimals used to get the user representation. - * @return {[]} - None. - */ - export circuit initializer( - name_: Maybe>, - symbol_: Maybe>, - decimals_:Uint<8> - ): [] { - _name = name_; - _symbol = symbol_; - _decimals = decimals_; - } - - /** - * @description Returns the token name. - * - * @return {Maybe>} - The token name. - */ - export circuit name(): Maybe> { - return _name; - } - - /** - * @description Returns the symbol of the token. - * - * @return {Maybe>} - The token name. - */ - export circuit symbol(): Maybe> { - return _symbol; - } - - /** - * @description Returns the number of decimals used to get its user representation. - * - * @return {Uint<8>} - The account's token balance. - */ - export circuit decimals(): Uint<8> { - return _decimals; - } - - /** - * @description Returns the value of tokens in existence. - * - * @return {Uint<128>} - The total supply of tokens. - */ - export circuit totalSupply(): Uint<128> { - return _totalSupply; - } - - /** - * @description Returns the value of tokens owned by `account`. - * - * @dev Manually checks if `account` is a key in the map and returns 0 if it is not. - * - * @param {account} - The public key or contract address to query. - * @return {Uint<128>} - The account's token balance. - */ - export circuit balanceOf(account: Either): Uint<128> { - if (!_balances.member(account)) { - return 0; - } - - return _balances.lookup(account); - } - - /** - * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` - * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. - * - * @dev Manually checks if `owner` and `spender` are keys in the map and returns 0 if they are not. - * - * @param {owner} - The public key or contract address of approver. - * @param {spender} - The public key or contract address of spender. - * @return {Uint<128>} - The `spender`'s allowance over `owner`'s tokens. - */ - export circuit allowance( - owner: Either, - spender: Either - ): Uint<128> { - if (!_allowances.member(owner) || !_allowances.lookup(owner).member(spender)) { - return 0; - } - - return _allowances.lookup(owner).lookup(spender); - } - - /** - * @description Moves a `value` amount of tokens from the caller's account to `to`. - * - * @dev We need to get the caller address from contracts and handle the transfer appropriately. - * This should include a callback to ensure the contract can safely receive tokens. - * - * @param {to} - The recipient of the transfer, either a user or a contract. - * @param {value} - The amount to transfer. - * @return {Boolean} - As per the IERC20 spec, this MUST return true. - */ - export circuit transfer(to: Either, value: Uint<128>): Boolean { - // TMP - Waiting for contract-to-contract calls to handle `right` with contract address - const owner = left(own_public_key()); - _transfer(owner, to, value); - return true; - } - - /** - * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. - * `value` is the deducted from the caller's allowance. - * - * @dev We need to get the caller address from contracts and handle the transfer appropriately. - * This should include a callback to ensure the contract can safely receive tokens. - * - * @param {from} - The current owner of the tokens for the transfer, either a user or a contract. - * @param {to} - The recipient of the transfer, either a user or a contract. - * @param {value} - The amount to transfer. - * @return {Boolean} - As per the IERC20 spec, this MUST return true. - */ - export circuit transferFrom( - from: Either, - to: Either, - value: Uint<128> - ): Boolean { - // TMP - Waiting for contract-to-contract calls to handle `right` with contract address - const spender = left(own_public_key()); - _spendAllowance(from, spender, value); - _transfer(from, to, value); - return true; - } - - /** - * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. - * - * @param {spender} - The Zswap key or ContractAddress that may spend on behalf of the caller. - * @param {value} - The amount of tokens the `spender` may spend. - * @return {Boolean} - Returns a boolean value indicating whether the operation succeeded. - */ - export circuit approve(spender: Either, value: Uint<128>): Boolean { - // TMP - Waiting for contract-to-contract calls to handle `right` with contract address - const owner = left(own_public_key()); - _approve(owner, spender, value); - return true; - } - - /** - * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. - * This internal function is equivalent to `approve`, and can be used to - * e.g. set automatic allowances for certain subsystems, etc. - * - * @param {owner} - The owner of the tokens. - * @param {spender} - The spender of the tokens. - * @param {value} - The amount of tokens `spender` may spend on behalf of `owner`. - * @return {[]} - None. - */ - export circuit _approve( - owner: Either, - spender: Either, - value: Uint<128> - ): [] { - assert !Utils_isKeyOrAddressZero(owner) "ERC20: invalid owner"; - assert !Utils_isKeyOrAddressZero(spender) "ERC20: invalid spender"; - if (!_allowances.member(owner)) { - // If owner doesn't exist, create and insert a new sub-map directly - _allowances.insert(owner, default, Uint<128>>>); - } - _allowances.lookup(owner).insert(spender, value); - } - - /** - * @description Moves a `value` amount of tokens from `from` to `to`. - * This internal function is equivalent to {transfer}, and can be used to - * e.g. implement automatic token fees, slashing mechanisms, etc. - * - * @param {from} - The owner of the tokens to transfer. - * @param {to} - The receipient of the transferred tokens. - * @param {value} - The amount of tokens to transfer. - * @return {[]} - None. - */ - export circuit _transfer( - from: Either, - to: Either, - value: Uint<128> - ): [] { - assert !Utils_isKeyOrAddressZero(from) "ERC20: invalid sender"; - assert !Utils_isKeyOrAddressZero(to) "ERC20: invalid receiver"; - - _update(from, to, value); - } - - /** - * @description Creates a `value` amount of tokens and assigns them to `account`, - * by transferring it from the zero address. Relies on the `update` mechanism. - * - * @param {account} - The recipient of tokens minted. - * @param {value} - The amount of tokens minted. - * @return {[]} - None. - */ - export circuit _mint( - account: Either, - value: Uint<128> - ): [] { - assert !Utils_isKeyOrAddressZero(account) "ERC20: invalid receiver"; - // Using the contract variant of 0 - // TODO: Look into if this matters - const zero_address = right(ContractAddress{ pad(32, "") }); - - _update(zero_address, account, value); - } - - /** - * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. - * Relies on the `_update` mechanism. - * - * @param {account} - The target owner of tokens to burn. - * @param {value} - The amount of tokens to burn. - * @return {[]} - None. - */ - export circuit _burn( - account: Either, - value: Uint<128> - ): [] { - assert !Utils_isKeyOrAddressZero(account) "ERC20: invalid sender"; - // Using the contract variant of 0 - // TODO: Look into if this matters - const zero_address = right(ContractAddress{ pad(32, "") }); - _update(account, zero_address, value); - } - - /** - * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` - * (or `to`) is the zero address. - * @dev Checks for a mint overflow in order to output a more readable error message. - * - * @param {from} - The original owner of the tokens moved (which is 0 if tokens are minted). - * @param {to} - The recipient of the tokens moved (which is 0 if tokens are burned). - * @param {value} - The amount of tokens moved from `from` to `to`. - * @return {[]} - None. - */ - export circuit _update( - from: Either, - to: Either, - value: Uint<128> - ): [] { - if (Utils_isKeyOrAddressZero(from)) { - // Mint - const MAX_UINT128 = 340282366920938463463374607431768211455; - assert MAX_UINT128 - _totalSupply >= value "ERC20: arithmetic overflow"; - - _totalSupply = _totalSupply + value as Uint<128>; - } else { - const fromBal = balanceOf(from); - assert fromBal >= value "ERC20: insufficient balance"; - _balances.insert(from, fromBal - value as Uint<128>); - } - - if (Utils_isKeyOrAddressZero(to)) { - // Burn - _totalSupply = _totalSupply - value as Uint<128>; - } else { - const toBal = balanceOf(to); - _balances.insert(to, toBal + value as Uint<128>); - } - } - - /** - * @description Updates `owner`'s allowance for `spender` based on spent `value`. - * Does not update the allowance value in case of infinite allowance. - * - * @param {owner} - The owner of the tokens. - * @param {spender} - The spender of the tokens. - * @param {value} - The amount of token allowance to spend. - * @return {[]} - None. - */ - export circuit _spendAllowance( - owner: Either, - spender: Either, - value: Uint<128> - ): [] { - // TODO: Look into improving design so we're not checking allowance member twice (here and in `_approve`) - assert (_allowances.member(owner) && _allowances.lookup(owner).member(spender)) "ERC20: insufficient allowance"; - - const currentAllowance = _allowances.lookup(owner).lookup(spender); - // TODO: improve readability of max_u128 - const MAX_UINT128 = 340282366920938463463374607431768211455; - if (currentAllowance < MAX_UINT128) { - assert currentAllowance >= value "ERC20: insufficient allowance"; - _approve(owner, spender, currentAllowance - value as Uint<128>); - } - } -} diff --git a/contracts/erc20/src/test/erc20.test.ts b/contracts/erc20/src/test/erc20.test.ts deleted file mode 100644 index 90d95413..00000000 --- a/contracts/erc20/src/test/erc20.test.ts +++ /dev/null @@ -1,493 +0,0 @@ -import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; -import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { ERC20Simulator } from './simulators/ERC20Simulator'; -import type { MaybeString } from './types/string'; -import * as utils from './utils/address'; - -const NO_STRING: MaybeString = { - is_some: false, - value: '', -}; -const NAME: MaybeString = { - is_some: true, - value: 'NAME', -}; -const SYMBOL: MaybeString = { - is_some: true, - value: 'SYMBOL', -}; -const DECIMALS: bigint = 18n; - -const AMOUNT: bigint = BigInt(250); -const MAX_UINT128 = BigInt(2 ** 128) - BigInt(1); - -const OWNER = String(Buffer.from('OWNER', 'ascii').toString('hex')).padStart( - 64, - '0', -); -const SPENDER = String( - Buffer.from('SPENDER', 'ascii').toString('hex'), -).padStart(64, '0'); -const UNAUTHORIZED = String( - Buffer.from('UNAUTHORIZED', 'ascii').toString('hex'), -).padStart(64, '0'); -const ZERO = String().padStart(64, '0'); -const Z_OWNER = utils.createEitherTestUser('OWNER'); -const Z_RECIPIENT = utils.createEitherTestUser('RECIPIENT'); -const Z_SPENDER = utils.createEitherTestUser('SPENDER'); -const Z_OTHER = utils.createEitherTestUser('OTHER'); - -let token: ERC20Simulator; -let caller: CoinPublicKey; - -describe('ERC20', () => { - describe('initializer and metadata', () => { - it('should initialize metadata', () => { - token = new ERC20Simulator(NAME, SYMBOL, DECIMALS); - - expect(token.name()).toEqual(NAME); - expect(token.symbol()).toEqual(SYMBOL); - expect(token.decimals()).toEqual(DECIMALS); - }); - - it('should initialize empty metadata', () => { - const NO_DECIMALS = 0n; - token = new ERC20Simulator(NO_STRING, NO_STRING, NO_DECIMALS); - - expect(token.name()).toEqual(NO_STRING); - expect(token.symbol()).toEqual(NO_STRING); - expect(token.decimals()).toEqual(NO_DECIMALS); - }); - }); - - beforeEach(() => { - token = new ERC20Simulator(NAME, SYMBOL, DECIMALS); - }); - - describe('totalSupply', () => { - it('returns 0 when there is no supply', () => { - expect(token.totalSupply()).toEqual(0n); - }); - - it('returns the amount of existing tokens when there is a supply', () => { - token._mint(Z_OWNER, AMOUNT); - expect(token.totalSupply()).toEqual(AMOUNT); - }); - }); - - describe('balanceOf', () => { - it('should return zero when requested account has no balance', () => { - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - - it('should return balance when requested account has tokens', () => { - token._mint(Z_OWNER, AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); - }); - - describe('transfer', () => { - beforeEach(() => { - token._mint(Z_OWNER, AMOUNT); - - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); - }); - - afterEach(() => { - expect(token.totalSupply()).toEqual(AMOUNT); - }); - - it('should transfer partial', () => { - const partialAmt = AMOUNT - 1n; - caller = OWNER; - const txSuccess = token.transfer(Z_RECIPIENT, partialAmt, caller); - - expect(txSuccess).toBe(true); - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); - }); - - it('should transfer full', () => { - caller = OWNER; - const txSuccess = token.transfer(Z_RECIPIENT, AMOUNT, caller); - - expect(txSuccess).toBe(true); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); - }); - - it('should fail with insufficient balance', () => { - caller = OWNER; - - expect(() => { - token.transfer(Z_RECIPIENT, AMOUNT + 1n, caller); - }).toThrow('ERC20: insufficient balance'); - }); - - it('should fail with transfer from zero', () => { - caller = ZERO; - - expect(() => { - token.transfer(Z_RECIPIENT, AMOUNT, caller); - }).toThrow('ERC20: invalid sender'); - }); - - it('should fail with transfer to zero', () => { - caller = OWNER; - - expect(() => { - token.transfer(utils.ZERO_ADDRESS, AMOUNT, caller); - }).toThrow('ERC20: invalid receiver'); - }); - - it('should allow transfer of 0 tokens', () => { - const txSuccess = token.transfer(Z_RECIPIENT, 0n, caller); - - expect(txSuccess).toBe(true); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(0n); - }); - - it('should handle transfer with empty _balances', () => { - caller = SPENDER; - - expect(() => { - token.transfer(Z_RECIPIENT, 1n, caller); - }).toThrow('ERC20: insufficient balance'); - }); - }); - - describe('approve', () => { - beforeEach(() => { - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - }); - - it('should approve and update allowance', () => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); - }); - - it('should approve and update allowance for multiple spenders', () => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); - - token.approve(Z_OTHER, AMOUNT, caller); - expect(token.allowance(Z_OWNER, Z_OTHER)).toEqual(AMOUNT); - - expect(token.allowance(Z_OWNER, Z_RECIPIENT)).toEqual(0n); - }); - - it('should fail when approve from zero', () => { - caller = ZERO; - - expect(() => { - token.approve(Z_SPENDER, AMOUNT, caller); - }).toThrow('ERC20: invalid owner'); - }); - - it('should fail when approve to zero', () => { - caller = OWNER; - - expect(() => { - token.approve(utils.ZERO_ADDRESS, AMOUNT, caller); - }).toThrow('ERC20: invalid spender'); - }); - - it('should transfer exact allowance and fail subsequent transfer', () => { - token._mint(Z_OWNER, AMOUNT); - caller = OWNER; - token.approve(Z_SPENDER, AMOUNT, caller); - - caller = SPENDER; - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, 1n, caller); - }).toThrow('ERC20: insufficient allowance'); - }); - - it('should allow approve of 0 tokens', () => { - caller = OWNER; - token.approve(Z_SPENDER, 0n, caller); - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - }); - - it('should handle allowance with empty _allowances', () => { - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - }); - }); - - describe('transferFrom', () => { - beforeEach(() => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); - token._mint(Z_OWNER, AMOUNT); - }); - - afterEach(() => { - expect(token.totalSupply()).toEqual(AMOUNT); - }); - - it('should transferFrom spender (partial)', () => { - caller = SPENDER; - const partialAmt = AMOUNT - 1n; - - const txSuccess = token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - partialAmt, - caller, - ); - expect(txSuccess).toBe(true); - - // Check balances - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); - // Check leftover allowance - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(1n); - }); - - it('should transferFrom spender (full)', () => { - caller = SPENDER; - - const txSuccess = token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - AMOUNT, - caller, - ); - expect(txSuccess).toBe(true); - - // Check balances - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); - // Check no allowance - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); - }); - - it('should transferFrom and not consume infinite allowance', () => { - caller = OWNER; - token.approve(Z_SPENDER, MAX_UINT128, caller); - - caller = SPENDER; - const txSuccess = token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - AMOUNT, - caller, - ); - expect(txSuccess).toBe(true); - - // Check balances - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); - // Check infinite allowance - expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(MAX_UINT128); - }); - - it('should fail when transfer amount exceeds allowance', () => { - caller = SPENDER; - - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n); - }).toThrow('ERC20: insufficient allowance'); - }); - - it('should fail when transfer amount exceeds balance', () => { - caller = OWNER; - // Increase allowance > balance - token.approve(Z_SPENDER, AMOUNT + 1n, caller); - - caller = SPENDER; - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n, caller); - }).toThrow('ERC20: insufficient balance'); - }); - - it('should fail when spender does not have allowance', () => { - caller = UNAUTHORIZED; - - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - }).toThrow('ERC20: insufficient allowance'); - }); - - it('should fail to transferFrom zero address', () => { - caller = ZERO; - - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); - }).toThrow('ERC20: insufficient allowance'); - }); - - it('should fail to transferFrom to the zero address', () => { - caller = SPENDER; - - expect(() => { - token.transferFrom(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT, caller); - }).toThrow('ERC20: invalid receiver'); - }); - }); - - describe('_transfer', () => { - beforeEach(() => { - token._mint(Z_OWNER, AMOUNT); - }); - - afterEach(() => { - expect(token.totalSupply()).toEqual(AMOUNT); - }); - - it('should update balances (partial)', () => { - const partialAmt = AMOUNT - 1n; - token._transfer(Z_OWNER, Z_RECIPIENT, partialAmt); - - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(partialAmt); - }); - }); - - describe('_mint', () => { - it('should mint and update supply', () => { - expect(token.totalSupply()).toEqual(0n); - - token._mint(Z_RECIPIENT, AMOUNT); - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT); - }); - - it('should catch mint overflow', () => { - token._mint(Z_RECIPIENT, MAX_UINT128); - - expect(() => { - token._mint(Z_RECIPIENT, 1n); - }).toThrow('ERC20: arithmetic overflow'); - }); - - it('should not mint to zero pubkey', () => { - expect(() => { - token._mint(utils.ZERO_KEY, AMOUNT); - }).toThrow('ERC20: invalid receiver'); - }); - - it('should not mint to zero contract address', () => { - expect(() => { - token._mint(utils.ZERO_ADDRESS, AMOUNT); - }).toThrow('ERC20: invalid receiver'); - }); - - it('should allow mint of 0 tokens', () => { - token._mint(Z_OWNER, 0n); - expect(token.totalSupply()).toEqual(0n); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - }); - - describe('_burn', () => { - beforeEach(() => { - token._mint(Z_OWNER, AMOUNT); - }); - - it('should burn tokens', () => { - token._burn(Z_OWNER, 1n); - - const afterBurn = AMOUNT - 1n; - expect(token.balanceOf(Z_OWNER)).toEqual(afterBurn); - expect(token.totalSupply()).toEqual(afterBurn); - }); - - it('should throw when burning from zero', () => { - expect(() => { - token._burn(utils.ZERO_KEY, AMOUNT); - }).toThrow('ERC20: invalid sender'); - }); - - it('should throw when burn amount is greater than balance', () => { - expect(() => { - token._burn(Z_OWNER, AMOUNT + 1n); - }).toThrow('ERC20: insufficient balance'); - }); - - it('should allow burn of 0 tokens', () => { - token._burn(Z_OWNER, 0n); - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); - }); - - describe('_update', () => { - it('should update from zero to non-zero (mint)', () => { - expect(token.totalSupply()).toEqual(0n); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - - token._update(utils.ZERO_KEY, Z_OWNER, AMOUNT); - - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); - - it('should catch overflow from zero to non-zero (mint)', () => { - token._update(utils.ZERO_KEY, Z_OWNER, MAX_UINT128); - - expect(() => { - token._update(utils.ZERO_KEY, Z_OWNER, 1n); - }).toThrow('ERC20: arithmetic overflow'); - }); - - describe('with minted tokens', () => { - beforeEach(() => { - token._update(utils.ZERO_ADDRESS, Z_OWNER, AMOUNT); - - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - }); - - it('should update from non-zero to zero (burn)', () => { - token._update(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); - - expect(token.totalSupply()).toEqual(0n); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - - it('should catch overflow from non-zero to zero (burn)', () => { - token._update(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); - - expect(() => { - token._update(Z_OWNER, utils.ZERO_ADDRESS, 1n); - }).toThrow('ERC20: insufficient balance'); - }); - - it('should update from non-zero to non-zero (transfer)', () => { - token._update(Z_OWNER, Z_RECIPIENT, AMOUNT - 1n); - - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); - }); - }); - }); - - describe('Multiple Operations', () => { - it('should handle mint → transfer → burn sequence', () => { - token._mint(Z_OWNER, AMOUNT); - expect(token.totalSupply()).toEqual(AMOUNT); - expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - - caller = OWNER; - token.transfer(Z_RECIPIENT, AMOUNT - 1n, caller); - expect(token.balanceOf(Z_OWNER)).toEqual(1n); - expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); - - token._burn(Z_OWNER, 1n); - expect(token.totalSupply()).toEqual(AMOUNT - 1n); - expect(token.balanceOf(Z_OWNER)).toEqual(0n); - }); - }); -}); diff --git a/contracts/erc20/src/test/mocks/MockERC20.compact b/contracts/erc20/src/test/mocks/MockERC20.compact deleted file mode 100644 index 2d2084f1..00000000 --- a/contracts/erc20/src/test/mocks/MockERC20.compact +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma language_version >= 0.15.0; - -import CompactStandardLibrary; - -import "../../ERC20" prefix ERC20_; - -export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; - -constructor( - _name: Maybe>, - _symbol: Maybe>, - _decimals:Uint<8> -) { - ERC20_initializer(_name, _symbol, _decimals); -} - -export circuit name(): Maybe> { - return ERC20_name(); -} - -export circuit symbol(): Maybe> { - return ERC20_symbol(); -} - -export circuit decimals(): Uint<8> { - return ERC20_decimals(); -} - -export circuit totalSupply(): Uint<128> { - return ERC20_totalSupply(); -} - -export circuit balanceOf(account: Either): Uint<128> { - return ERC20_balanceOf(account); -} - -export circuit allowance( - owner: Either, - spender: Either -): Uint<128> { - return ERC20_allowance(owner, spender); -} - -export circuit transfer(to: Either, value: Uint<128>): Boolean { - return ERC20_transfer(to, value); -} - -export circuit transferFrom( - from: Either, - to: Either, - value: Uint<128> -): Boolean { - return ERC20_transferFrom(from, to, value); -} - -export circuit approve(spender: Either, value: Uint<128>): Boolean { - return ERC20_approve(spender, value); -} - -export circuit _approve( - owner: Either, - spender: Either, - value: Uint<128> -): [] { - return ERC20__approve(owner, spender, value); -} - -export circuit _transfer( - from: Either, - to: Either, - value: Uint<128> -): [] { - return ERC20__transfer(from, to, value); -} - -export circuit _mint( - account: Either, - value: Uint<128> -): [] { - return ERC20__mint(account, value); -} - -export circuit _burn( - account: Either, - value: Uint<128> -): [] { - return ERC20__burn(account, value); -} - -export circuit _update( - from: Either, - to: Either, - value: Uint<128> -): [] { - return ERC20__update(from, to, value); -} - -export circuit _spendAllowance( - owner: Either, - spender: Either, - value: Uint<128> -): [] { - return ERC20__spendAllowance(owner, spender, value); -} diff --git a/contracts/erc20/src/test/simulators/ERC20Simulator.ts b/contracts/erc20/src/test/simulators/ERC20Simulator.ts deleted file mode 100644 index 3e48f543..00000000 --- a/contracts/erc20/src/test/simulators/ERC20Simulator.ts +++ /dev/null @@ -1,360 +0,0 @@ -import { - type CircuitContext, - type CoinPublicKey, - type ContractState, - QueryContext, - constructorContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; -import { - type ContractAddress, - type Either, - type Ledger, - Contract as MockERC20, - type ZswapCoinPublicKey, - ledger, -} from '../../artifacts/MockERC20/contract/index.cjs'; // Combined imports -import { - type ERC20PrivateState, - ERC20Witnesses, -} from '../../witnesses/ERC20Witnesses'; -import type { MaybeString } from '../types/string'; -import type { IContractSimulator } from './../types/test'; - -/** - * @description A simulator implementation of an erc20 contract for testing purposes. - * @template P - The private state type, fixed to ERC20PrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. - */ -export class ERC20Simulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockERC20; - - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor(name: MaybeString, symbol: MaybeString, decimals: bigint) { - this.contract = new MockERC20(ERC20Witnesses); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)), - name, - symbol, - decimals, - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type ERC20PrivateState. - */ - public getCurrentPrivateState(): ERC20PrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; - } - - /** - * @description Returns the token name. - * @returns The token name. - */ - public name(): MaybeString { - return this.contract.impureCircuits.name(this.circuitContext).result; - } - - /** - * @description Returns the symbol of the token. - * @returns The token name. - */ - public symbol(): MaybeString { - return this.contract.impureCircuits.symbol(this.circuitContext).result; - } - - /** - * @description Returns the number of decimals used to get its user representation. - * @returns The account's token balance. - */ - public decimals(): bigint { - return this.contract.impureCircuits.decimals(this.circuitContext).result; - } - - /** - * @description Returns the value of tokens in existence. - * @returns The total supply of tokens. - */ - public totalSupply(): bigint { - return this.contract.impureCircuits.totalSupply(this.circuitContext).result; - } - - /** - * @description Returns the value of tokens owned by `account`. - * @param account The public key or contract address to query. - * @returns The account's token balance. - */ - public balanceOf( - account: Either, - ): bigint { - return this.contract.impureCircuits.balanceOf(this.circuitContext, account) - .result; - } - - /** - * @description Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` - * through `transferFrom`. This value changes when `approve` or `transferFrom` are called. - * @param owner The public key or contract address of approver. - * @param spender The public key or contract address of spender. - * @returns The `spender`'s allowance over `owner`'s tokens. - */ - public allowance( - owner: Either, - spender: Either, - ): bigint { - return this.contract.impureCircuits.allowance( - this.circuitContext, - owner, - spender, - ).result; - } - - /** - * @description Moves a `value` amount of tokens from the caller's account to `to`. - * @param to The recipient of the transfer, either a user or a contract. - * @param value The amount to transfer. - * @param sender The simulated caller. - * @returns As per the IERC20 spec, this MUST return true. - */ - public transfer( - to: Either, - value: bigint, - sender?: CoinPublicKey, - ): boolean { - const res = this.contract.impureCircuits.transfer( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - to, - value, - ); - - this.circuitContext = res.context; - return res.result; - } - - /** - * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. - * `value` is the deducted from the caller's allowance. - * @param from The current owner of the tokens for the transfer, either a user or a contract. - * @param to The recipient of the transfer, either a user or a contract. - * @param value The amount to transfer. - * @param sender The simulated caller. - * @returns As per the IERC20 spec, this MUST return true. - */ - public transferFrom( - from: Either, - to: Either, - value: bigint, - sender?: CoinPublicKey, - ): boolean { - const res = this.contract.impureCircuits.transferFrom( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, - to, - value, - ); - - this.circuitContext = res.context; - return res.result; - } - - /** - * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. - * @param spender The Zswap key or ContractAddress that may spend on behalf of the caller. - * @param value The amount of tokens the `spender` may spend. - * @param sender The simulated caller. - * @returns Returns a boolean value indicating whether the operation succeeded. - */ - public approve( - spender: Either, - value: bigint, - sender?: CoinPublicKey, - ): boolean { - const res = this.contract.impureCircuits.approve( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - spender, - value, - ); - - this.circuitContext = res.context; - return res.result; - } - - /// - /// Internal - /// - - /** - * @description Sets `value` as the allowance of `spender` over the `owner`'s tokens. - * This internal function is equivalent to `approve`, and can be used to - * e.g. set automatic allowances for certain subsystems, etc. - * @param owner The owner of the tokens. - * @param spender The spender of the tokens. - * @param value The amount of tokens `spender` may spend on behalf of `owner`. - * @returns None. - */ - public _approve( - owner: Either, - spender: Either, - value: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._approve( - this.circuitContext, - owner, - spender, - value, - ).context; - } - - /** - * @description Moves a `value` amount of tokens from `from` to `to`. - * This internal function is equivalent to {transfer}, and can be used to - * e.g. implement automatic token fees, slashing mechanisms, etc. - * @param from The owner of the tokens to transfer. - * @param to The receipient of the transferred tokens. - * @param value The amount of tokens to transfer. - */ - public _transfer( - from: Either, - to: Either, - value: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._transfer( - this.circuitContext, - from, - to, - value, - ).context; - } - - /** - * @description Creates a `value` amount of tokens and assigns them to `account`, - * by transferring it from the zero address. Relies on the `update` mechanism. - * @param account The recipient of tokens minted. - * @param value The amount of tokens minted. - */ - public _mint( - account: Either, - value: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._mint( - this.circuitContext, - account, - value, - ).context; - } - - /** - * @description Destroys a `value` amount of tokens from `account`, lowering the total supply. - * Relies on the `_update` mechanism. - * @param account The target owner of tokens to burn. - * @param value The amount of tokens to burn. - */ - public _burn( - account: Either, - value: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._burn( - this.circuitContext, - account, - value, - ).context; - } - - /** - * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` - * (or `to`) is the zero address. - * @param from The original owner of the tokens moved (which is 0 if tokens are minted). - * @param to The recipient of the tokens moved (which is 0 if tokens are burned). - * @param value The amount of tokens moved from `from` to `to`. - */ - public _update( - from: Either, - to: Either, - value: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._update( - this.circuitContext, - from, - to, - value, - ).context; - } - - /** - * @description Updates `owner`'s allowance for `spender` based on spent `value`. - * Does not update the allowance value in case of infinite allowance. - * @param owner The owner of the tokens. - * @param spender The spender of the tokens. - * @param value The amount of token allowance to spend. - */ - public _spendAllowance( - owner: Either, - spender: Either, - value: bigint, - ) { - this.circuitContext = this.contract.impureCircuits._spendAllowance( - this.circuitContext, - owner, - spender, - value, - ).context; - } -} diff --git a/contracts/erc20/src/test/types/test.ts b/contracts/erc20/src/test/types/test.ts deleted file mode 100644 index 7a909543..00000000 --- a/contracts/erc20/src/test/types/test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { - CircuitContext, - ContractState, -} from '@midnight-ntwrk/compact-runtime'; - -/** - * Generic interface for mock contract implementations. - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - */ -export interface IContractSimulator { - /** The contract's deployed address. */ - readonly contractAddress: string; - - /** The current circuit context. */ - circuitContext: CircuitContext

; - - /** Retrieves the current ledger state. */ - getCurrentPublicState(): L; - - /** Retrieves the current private state. */ - getCurrentPrivateState(): P; - - /** Retrieves the current contract state. */ - getCurrentContractState(): ContractState; -} diff --git a/contracts/erc20/src/test/utils/address.ts b/contracts/erc20/src/test/utils/address.ts deleted file mode 100644 index 3580e196..00000000 --- a/contracts/erc20/src/test/utils/address.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { - convert_bigint_to_Uint8Array, - encodeCoinPublicKey, -} from '@midnight-ntwrk/compact-runtime'; -import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import type * as Compact from '../../artifacts/MockERC20/contract/index.cjs'; - -const PREFIX_ADDRESS = '0200'; - -export const pad = (s: string, n: number): Uint8Array => { - const encoder = new TextEncoder(); - const utf8Bytes = encoder.encode(s); - if (n < utf8Bytes.length) { - throw new Error(`The padded length n must be at least ${utf8Bytes.length}`); - } - const paddedArray = new Uint8Array(n); - paddedArray.set(utf8Bytes); - return paddedArray; -}; - -/** - * @description Generates ZswapCoinPublicKey from `str` for testing purposes. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; -}; - -/** - * @description Generates ContractAddress from `str` for testing purposes. - * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToAddress = (str: string): Compact.ContractAddress => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); - return { bytes: encodeContractAddress(fullAddress) }; -}; - -/** - * @description Generates an Either object for ZswapCoinPublicKey for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ZswapCoinPublicKey. - */ -export const createEitherTestUser = (str: string) => { - return { - is_left: true, - left: encodeToPK(str), - right: encodeToAddress(''), - }; -}; - -/** - * @description Generates an Either object for ContractAddress for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ContractAddress. - */ -export const createEitherTestContractAddress = (str: string) => { - return { - is_left: false, - left: encodeToPK(''), - right: encodeToAddress(str), - }; -}; - -export const ZERO_KEY = { - is_left: true, - left: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, - right: encodeToAddress(''), -}; - -export const ZERO_ADDRESS = { - is_left: false, - left: encodeToPK(''), - right: { bytes: convert_bigint_to_Uint8Array(32, BigInt(0)) }, -}; diff --git a/contracts/erc20/src/test/utils/test.ts b/contracts/erc20/src/test/utils/test.ts deleted file mode 100644 index 0a967d12..00000000 --- a/contracts/erc20/src/test/utils/test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - QueryContext, - emptyZswapLocalState, -} from '@midnight-ntwrk/compact-runtime'; -<<<<<<< HEAD -import type { IContractSimulator } from '../types/test.js'; -======= -import type { IContractSimulator } from '../types/test'; ->>>>>>> b6f5215 (Add pausable (#22)) - -/** - * Constructs a `CircuitContext` from the given state and sender information. - * - * This is typically used at runtime to provide the necessary context - * for executing circuits, including contract state, private state, - * sender identity, and transaction data. - * - * @template P - The type of the contract's private state. - * @param privateState - The current private state of the contract. - * @param contractState - The full contract state, including public and private data. - * @param sender - The public key of the sender (used in the circuit). - * @param contractAddress - The address of the deployed contract. - * @returns A fully populated `CircuitContext` for circuit execution. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContext

( - privateState: P, - contractState: ContractState, - sender: CoinPublicKey, - contractAddress: ContractAddress, -): CircuitContext

{ - return { - originalState: contractState, - currentPrivateState: privateState, - transactionContext: new QueryContext(contractState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} - -/** - * Prepares a new `CircuitContext` using the given sender and contract. - * - * Useful for mocking or updating the circuit context with a custom sender. - * - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - * @template C - The specific type of the contract implementing `MockContract`. - * @param contract - The contract instance implementing `MockContract`. - * @param sender - The public key to set as the sender in the new circuit context. - * @returns A new `CircuitContext` with the sender and updated context values. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContextSender< - P, - L, - C extends IContractSimulator, ->(contract: C, sender: CoinPublicKey): CircuitContext

{ - const currentPrivateState = contract.getCurrentPrivateState(); - const originalState = contract.getCurrentContractState(); - const contractAddress = contract.contractAddress; - - return { - originalState, - currentPrivateState, - transactionContext: new QueryContext(originalState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} diff --git a/contracts/erc20/src/witnesses/ERC20Witnesses.ts b/contracts/erc20/src/witnesses/ERC20Witnesses.ts deleted file mode 100644 index ed372fb7..00000000 --- a/contracts/erc20/src/witnesses/ERC20Witnesses.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This is how we type an empty object. -export type ERC20PrivateState = Record; -export const ERC20Witnesses = {}; diff --git a/contracts/erc20/tsconfig.build.json b/contracts/erc20/tsconfig.build.json deleted file mode 100644 index f1132509..00000000 --- a/contracts/erc20/tsconfig.build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["src/test/**/*.ts"], - "compilerOptions": {} -} diff --git a/contracts/erc20/tsconfig.json b/contracts/erc20/tsconfig.json deleted file mode 100644 index 3e90b0a9..00000000 --- a/contracts/erc20/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "include": ["src/**/*.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - "declaration": true, - "lib": ["ESNext"], - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "node", - "allowJs": true, - "forceConsistentCasingInFileNames": true, - "noImplicitAny": true, - "strict": true, - "isolatedModules": true, - "sourceMap": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "skipLibCheck": true - } -} diff --git a/contracts/erc20/vitest.config.ts b/contracts/erc20/vitest.config.ts deleted file mode 100644 index 785b792e..00000000 --- a/contracts/erc20/vitest.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from 'vitest/config'; - -export default defineConfig({ - test: { - globals: true, - environment: 'node', - include: ['src/test/**/*.test.ts'], - reporters: 'verbose', - }, -}); diff --git a/contracts/fungibleToken/package.json b/contracts/fungibleToken/package.json index 335abf5d..2e4f84ed 100644 --- a/contracts/fungibleToken/package.json +++ b/contracts/fungibleToken/package.json @@ -32,4 +32,4 @@ "typescript": "^5.2.2", "vitest": "^3.1.3" } -} +} \ No newline at end of file diff --git a/contracts/fungibleToken/src/FungibleToken.compact b/contracts/fungibleToken/src/FungibleToken.compact index 4d2f01d5..ec6387cf 100644 --- a/contracts/fungibleToken/src/FungibleToken.compact +++ b/contracts/fungibleToken/src/FungibleToken.compact @@ -66,7 +66,6 @@ module FungibleToken { export sealed ledger _name: Opaque<"string">; export sealed ledger _symbol: Opaque<"string">; export sealed ledger _decimals: Uint<8>; - /** * @description Initializes the contract by setting the name, symbol, and decimals. * @dev This MUST be called in the implementing contract's constructor. Failure to do so diff --git a/contracts/fungibleToken/src/test/simulators/FungibleTokenSimulator.ts b/contracts/fungibleToken/src/test/simulators/FungibleTokenSimulator.ts index 87ecba0b..7fa793b8 100644 --- a/contracts/fungibleToken/src/test/simulators/FungibleTokenSimulator.ts +++ b/contracts/fungibleToken/src/test/simulators/FungibleTokenSimulator.ts @@ -27,8 +27,7 @@ import type { IContractSimulator } from '../types/test.js'; * @template L - The ledger type, fixed to Contract.Ledger. */ export class FungibleTokenSimulator - implements IContractSimulator -{ + implements IContractSimulator { /** @description The underlying contract instance managing contract logic. */ readonly contract: MockFungibleToken; diff --git a/contracts/fungibleToken/src/test/utils/test.ts b/contracts/fungibleToken/src/test/utils/test.ts index 9fd2d4f6..07e86e88 100644 --- a/contracts/fungibleToken/src/test/utils/test.ts +++ b/contracts/fungibleToken/src/test/utils/test.ts @@ -8,6 +8,7 @@ import { } from '@midnight-ntwrk/compact-runtime'; import type { IContractSimulator } from '../types/test.js'; + /** * Constructs a `CircuitContext` from the given state and sender information. * diff --git a/contracts/fungibleToken/tsconfig.json b/contracts/fungibleToken/tsconfig.json index d6c626dc..b6b69fc7 100644 --- a/contracts/fungibleToken/tsconfig.json +++ b/contracts/fungibleToken/tsconfig.json @@ -1,10 +1,14 @@ { - "include": ["src/**/*.ts"], + "include": [ + "src/**/*.ts" + ], "compilerOptions": { "rootDir": "src", "outDir": "dist", "declaration": true, - "lib": ["ES2022"], + "lib": [ + "ES2022" + ], "target": "ES2022", "module": "nodenext", "moduleResolution": "nodenext", diff --git a/contracts/utils/src/test/mocks/MockUtils.compact b/contracts/utils/src/test/mocks/MockUtils.compact index b559380f..26c5a817 100644 --- a/contracts/utils/src/test/mocks/MockUtils.compact +++ b/contracts/utils/src/test/mocks/MockUtils.compact @@ -38,3 +38,18 @@ export pure circuit emptyString(): Opaque<"string"> { return Utils_isKeyOrAddressZero(keyOrAddress); >>>>>>> b6f5215 (Add pausable (#22)) } + +export pure circuit isKeyOrAddressEqual( + keyOrAddress: Either, + other: Either +): Boolean { + return Utils_isKeyOrAddressEqual(keyOrAddress, other); +} + +export pure circuit isKeyZero(key: ZswapCoinPublicKey): Boolean { + return Utils_isKeyZero(key); +} + +export pure circuit isContractAddress(keyOrAddress: Either): Boolean { + return Utils_isContractAddress(keyOrAddress); +} diff --git a/contracts/utils/src/test/simulators/UtilsSimulator.ts b/contracts/utils/src/test/simulators/UtilsSimulator.ts index 3a564524..04a9df12 100644 --- a/contracts/utils/src/test/simulators/UtilsSimulator.ts +++ b/contracts/utils/src/test/simulators/UtilsSimulator.ts @@ -6,7 +6,6 @@ import { } from '@midnight-ntwrk/compact-runtime'; import { sampleContractAddress } from '@midnight-ntwrk/zswap'; import { -<<<<<<< HEAD type ContractAddress, type Either, type Ledger, @@ -19,19 +18,6 @@ import { UtilsWitnesses, } from '../../witnesses/UtilsWitnesses.js'; import type { IContractSimulator } from '../types/test.js'; -======= - type Ledger, - Contract as MockUtils, - type ZswapCoinPublicKey, - ledger, -} from '../../artifacts/MockUtils/contract/index.cjs'; // Combined imports -import { - type UtilsPrivateState, - UtilsWitnesses, -} from '../../witnesses/UtilsWitnesses'; -import type { IContractSimulator } from '../types/test'; -import { UtilsPrivateState, UtilsWitnesses } from '../../witnesses/UtilsWitnesses'; ->>>>>>> b6f5215 (Add pausable (#22)) /** * @description A simulator implementation of an utils contract for testing purposes. @@ -39,8 +25,7 @@ import { UtilsPrivateState, UtilsWitnesses } from '../../witnesses/UtilsWitnesse * @template L - The ledger type, fixed to Contract.Ledger. */ export class UtilsSimulator - implements IContractSimulator -{ + implements IContractSimulator { /** @description The underlying contract instance managing contract logic. */ readonly contract: MockUtils; @@ -54,24 +39,12 @@ export class UtilsSimulator * @description Initializes the mock contract. */ constructor() { -<<<<<<< HEAD this.contract = new MockUtils(UtilsWitnesses); -======= - this.contract = new MockUtils( - UtilsWitnesses, - ); ->>>>>>> b6f5215 (Add pausable (#22)) const { currentPrivateState, currentContractState, currentZswapLocalState, -<<<<<<< HEAD } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); -======= - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)) - ); ->>>>>>> b6f5215 (Add pausable (#22)) this.circuitContext = { currentPrivateState, currentZswapLocalState, @@ -113,7 +86,6 @@ export class UtilsSimulator * @param keyOrAddress The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @returns Returns true if `keyOrAddress` is zero. */ -<<<<<<< HEAD public isKeyOrAddressZero( keyOrAddress: Either, ): boolean { @@ -165,16 +137,12 @@ export class UtilsSimulator keyOrAddress, ).result; } - /** * @description A helper function that returns the empty string: "" * @returns The empty string: "" */ public emptyString(): string { return this.contract.circuits.emptyString(this.circuitContext).result; -======= - public isKeyOrAddressZero(keyOrAddress: Either): boolean { - return this.contract.circuits.isKeyOrAddressZero(this.circuitContext, keyOrAddress).result; ->>>>>>> b6f5215 (Add pausable (#22)) + } } diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index 33214ba5..be9b16fc 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -108,4 +108,52 @@ describe('Utils', () => { >>>>>>> b6f5215 (Add pausable (#22)) }); }); + + describe('isKeyOrAddressEqual', () => { + it('should return true for two matching pubkeys', () => { + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_SOME_KEY)).toBe(true); + }); + + it('should return true for two matching contract addresses', () => { + expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, SOME_CONTRACT)).toBe( + true, + ); + }); + + it('should return false for two different pubkeys', () => { + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_OTHER_KEY)).toBe(false); + }); + + it('should return false for two different contract addresses', () => { + expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, OTHER_CONTRACT)).toBe( + false, + ); + }); + + it('should return false for two different address types', () => { + expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, SOME_CONTRACT)).toBe( + false, + ); + }); + }); + + describe('isKeyZero', () => { + it('should return zero for the zero address', () => { + expect(contract.isKeyZero(contractUtils.ZERO_KEY.left)).toBe(true); + }); + + it('should not return zero for nonzero addresses', () => { + expect(contract.isKeyZero(Z_SOME_KEY.left)).toBe(false); + }); + }); + + describe('isContractAddress', () => { + it('should return true if ContractAddress', () => { + expect(contract.isContractAddress(SOME_CONTRACT)).toBe(true); + }); + + it('should return false ZswapCoinPublicKey', () => { + expect(contract.isContractAddress(Z_SOME_KEY)).toBe(false); + }); + }); }); diff --git a/yarn.lock b/yarn.lock index b0301cf4..ecc09516 100644 --- a/yarn.lock +++ b/yarn.lock @@ -657,6 +657,13 @@ __metadata: languageName: node linkType: hard +"@types/estree@npm:^1.0.0": + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099 + languageName: node + linkType: hard + "@types/node@npm:22.14.0": version: 22.14.0 resolution: "@types/node@npm:22.14.0" From 01ffba623b69f6d97997e571919357e99f64a090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 26 Jun 2025 03:00:47 -0400 Subject: [PATCH 281/282] Update yarn.lock --- yarn.lock | 168 +++++++++++++++++++++++++++--------------------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/yarn.lock b/yarn.lock index ecc09516..f904025d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -466,142 +466,142 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.44.0" +"@rollup/rollup-android-arm-eabi@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.44.1" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-android-arm64@npm:4.44.0" +"@rollup/rollup-android-arm64@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-android-arm64@npm:4.44.1" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-darwin-arm64@npm:4.44.0" +"@rollup/rollup-darwin-arm64@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-darwin-arm64@npm:4.44.1" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-darwin-x64@npm:4.44.0" +"@rollup/rollup-darwin-x64@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-darwin-x64@npm:4.44.1" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.44.0" +"@rollup/rollup-freebsd-arm64@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.44.1" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-freebsd-x64@npm:4.44.0" +"@rollup/rollup-freebsd-x64@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-freebsd-x64@npm:4.44.1" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.44.0" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.44.1" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.44.0" +"@rollup/rollup-linux-arm-musleabihf@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.44.1" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.44.0" +"@rollup/rollup-linux-arm64-gnu@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.44.1" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.44.0" +"@rollup/rollup-linux-arm64-musl@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.44.1" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-loongarch64-gnu@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.44.0" +"@rollup/rollup-linux-loongarch64-gnu@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.44.1" conditions: os=linux & cpu=loong64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-powerpc64le-gnu@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.44.0" +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.44.1" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.44.0" +"@rollup/rollup-linux-riscv64-gnu@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.44.1" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-musl@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.44.0" +"@rollup/rollup-linux-riscv64-musl@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.44.1" conditions: os=linux & cpu=riscv64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.44.0" +"@rollup/rollup-linux-s390x-gnu@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.44.1" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.44.0" +"@rollup/rollup-linux-x64-gnu@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.44.1" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.44.0" +"@rollup/rollup-linux-x64-musl@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.44.1" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.44.0" +"@rollup/rollup-win32-arm64-msvc@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.44.1" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.44.0" +"@rollup/rollup-win32-ia32-msvc@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.44.1" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.44.0": - version: 4.44.0 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.44.0" +"@rollup/rollup-win32-x64-msvc@npm:4.44.1": + version: 4.44.1 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.44.1" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -2023,29 +2023,29 @@ __metadata: linkType: hard "rollup@npm:^4.40.0": - version: 4.44.0 - resolution: "rollup@npm:4.44.0" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.44.0" - "@rollup/rollup-android-arm64": "npm:4.44.0" - "@rollup/rollup-darwin-arm64": "npm:4.44.0" - "@rollup/rollup-darwin-x64": "npm:4.44.0" - "@rollup/rollup-freebsd-arm64": "npm:4.44.0" - "@rollup/rollup-freebsd-x64": "npm:4.44.0" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.44.0" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.44.0" - "@rollup/rollup-linux-arm64-gnu": "npm:4.44.0" - "@rollup/rollup-linux-arm64-musl": "npm:4.44.0" - "@rollup/rollup-linux-loongarch64-gnu": "npm:4.44.0" - "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.44.0" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.44.0" - "@rollup/rollup-linux-riscv64-musl": "npm:4.44.0" - "@rollup/rollup-linux-s390x-gnu": "npm:4.44.0" - "@rollup/rollup-linux-x64-gnu": "npm:4.44.0" - "@rollup/rollup-linux-x64-musl": "npm:4.44.0" - "@rollup/rollup-win32-arm64-msvc": "npm:4.44.0" - "@rollup/rollup-win32-ia32-msvc": "npm:4.44.0" - "@rollup/rollup-win32-x64-msvc": "npm:4.44.0" + version: 4.44.1 + resolution: "rollup@npm:4.44.1" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.44.1" + "@rollup/rollup-android-arm64": "npm:4.44.1" + "@rollup/rollup-darwin-arm64": "npm:4.44.1" + "@rollup/rollup-darwin-x64": "npm:4.44.1" + "@rollup/rollup-freebsd-arm64": "npm:4.44.1" + "@rollup/rollup-freebsd-x64": "npm:4.44.1" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.44.1" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.44.1" + "@rollup/rollup-linux-arm64-gnu": "npm:4.44.1" + "@rollup/rollup-linux-arm64-musl": "npm:4.44.1" + "@rollup/rollup-linux-loongarch64-gnu": "npm:4.44.1" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.44.1" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.44.1" + "@rollup/rollup-linux-riscv64-musl": "npm:4.44.1" + "@rollup/rollup-linux-s390x-gnu": "npm:4.44.1" + "@rollup/rollup-linux-x64-gnu": "npm:4.44.1" + "@rollup/rollup-linux-x64-musl": "npm:4.44.1" + "@rollup/rollup-win32-arm64-msvc": "npm:4.44.1" + "@rollup/rollup-win32-ia32-msvc": "npm:4.44.1" + "@rollup/rollup-win32-x64-msvc": "npm:4.44.1" "@types/estree": "npm:1.0.8" fsevents: "npm:~2.3.2" dependenciesMeta: @@ -2093,7 +2093,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10/2182fc751734277972c011bf62a07cd01de44aaa408f29d3be51b6c7373aa179c9e20d5b9b9fa46268c7d65fc8edb033243f501495465b13dd05d1f99635a7fa + checksum: 10/4130fcc4fb7df4364bfbdf78f277c0c2afc881812b3d01bd498b709da180ce69ff359af003d187d7c554576956dbc66d85468f4fc62b4b42b87839cd095ee9fd languageName: node linkType: hard From 4256f726e6c0e05f1584d5f76356870577eba7bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9F=A3=20=E2=82=AC=E2=82=A5=E2=84=B5=E2=88=AA=E2=84=93?= =?UTF-8?q?=20=E2=9F=A2?= <34749913+emnul@users.noreply.github.com> Date: Thu, 26 Jun 2025 04:27:59 -0400 Subject: [PATCH 282/282] Merge --- compact/package.json | 2 +- contracts/fungibleToken/package.json | 2 +- contracts/utils/package.json | 2 +- contracts/utils/src/test/Pausable.test.ts | 9 --- .../test/simulators/InitializableSimulator.ts | 25 -------- contracts/utils/src/test/utils.test.ts | 63 ------------------- contracts/utils/src/test/utils/test.ts | 2 +- .../src/witnesses/MockInitializable.compact | 14 ----- docs/package.json | 2 +- package.json | 2 +- yarn.lock | 40 +++--------- 11 files changed, 14 insertions(+), 149 deletions(-) delete mode 100644 contracts/utils/src/witnesses/MockInitializable.compact diff --git a/compact/package.json b/compact/package.json index 29b62262..786f6b0c 100644 --- a/compact/package.json +++ b/compact/package.json @@ -37,4 +37,4 @@ "log-symbols": "^7.0.0", "ora": "^8.2.0" } -} \ No newline at end of file +} diff --git a/contracts/fungibleToken/package.json b/contracts/fungibleToken/package.json index 2e4f84ed..335abf5d 100644 --- a/contracts/fungibleToken/package.json +++ b/contracts/fungibleToken/package.json @@ -32,4 +32,4 @@ "typescript": "^5.2.2", "vitest": "^3.1.3" } -} \ No newline at end of file +} diff --git a/contracts/utils/package.json b/contracts/utils/package.json index 490074d0..5408a32e 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -33,4 +33,4 @@ "typescript": "^5.2.2", "vitest": "^3.1.3" } -} \ No newline at end of file +} diff --git a/contracts/utils/src/test/Pausable.test.ts b/contracts/utils/src/test/Pausable.test.ts index ebd0b27f..94662b0c 100644 --- a/contracts/utils/src/test/Pausable.test.ts +++ b/contracts/utils/src/test/Pausable.test.ts @@ -1,10 +1,5 @@ -<<<<<<< HEAD import { beforeEach, describe, expect, it } from 'vitest'; import { PausableSimulator } from './simulators/PausableSimulator.js'; -======= -import { it, describe, expect } from '@jest/globals'; -import { PausableSimulator } from './simulators/PausableSimulator'; ->>>>>>> b6f5215 (Add pausable (#22)) let pausable: PausableSimulator; @@ -46,11 +41,7 @@ describe('Pausable', () => { }); it('should not throw when calling assertPaused', () => { -<<<<<<< HEAD pausable.assertPaused(); -======= - pausable.assertPaused(); ->>>>>>> b6f5215 (Add pausable (#22)) }); it('should throw when calling assertNotPaused', () => { diff --git a/contracts/utils/src/test/simulators/InitializableSimulator.ts b/contracts/utils/src/test/simulators/InitializableSimulator.ts index c8e36cf7..bdc89da2 100644 --- a/contracts/utils/src/test/simulators/InitializableSimulator.ts +++ b/contracts/utils/src/test/simulators/InitializableSimulator.ts @@ -1,4 +1,3 @@ -<<<<<<< HEAD import { type CircuitContext, type ContractState, @@ -16,12 +15,6 @@ import { InitializableWitnesses, } from '../../witnesses/InitializableWitnesses.js'; import type { IContractSimulator } from '../types/test.js'; -======= -import { type CircuitContext, type ContractState, QueryContext, sampleContractAddress, constructorContext } from '@midnight-ntwrk/compact-runtime'; -import { Contract as MockInitializable, type Ledger, ledger } from '../../artifacts/MockInitializable/contract/index.cjs'; -import type { IContractSimulator } from '../types/test'; -import { InitializablePrivateState, InitializableWitnesses } from '../../witnesses/InitializableWitnesses'; ->>>>>>> b6f5215 (Add pausable (#22)) /** * @description A simulator implementation of an utils contract for testing purposes. @@ -50,13 +43,7 @@ export class InitializableSimulator currentPrivateState, currentContractState, currentZswapLocalState, -<<<<<<< HEAD } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); -======= - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)) - ); ->>>>>>> b6f5215 (Add pausable (#22)) this.circuitContext = { currentPrivateState, currentZswapLocalState, @@ -98,13 +85,9 @@ export class InitializableSimulator * @returns None. */ public initialize() { -<<<<<<< HEAD this.circuitContext = this.contract.impureCircuits.initialize( this.circuitContext, ).context; -======= - this.circuitContext = this.contract.impureCircuits.initialize(this.circuitContext).context; ->>>>>>> b6f5215 (Add pausable (#22)) } /** @@ -113,12 +96,8 @@ export class InitializableSimulator * @throws Will throw "Initializable: contract not initialized" if the contract is not initialized. */ public assertInitialized() { -<<<<<<< HEAD return this.contract.impureCircuits.assertInitialized(this.circuitContext) .result; -======= - return this.contract.impureCircuits.assertInitialized(this.circuitContext).result; ->>>>>>> b6f5215 (Add pausable (#22)) } /** @@ -127,12 +106,8 @@ export class InitializableSimulator * @throws Will throw "Initializable: contract already initialized" if the contract is already initialized. */ public assertNotInitialized() { -<<<<<<< HEAD return this.contract.impureCircuits.assertNotInitialized( this.circuitContext, ).result; -======= - return this.contract.impureCircuits.assertNotInitialized(this.circuitContext).result; ->>>>>>> b6f5215 (Add pausable (#22)) } } diff --git a/contracts/utils/src/test/utils.test.ts b/contracts/utils/src/test/utils.test.ts index be9b16fc..7ff600f7 100644 --- a/contracts/utils/src/test/utils.test.ts +++ b/contracts/utils/src/test/utils.test.ts @@ -1,11 +1,6 @@ -<<<<<<< HEAD import { describe, expect, it } from 'vitest'; import { UtilsSimulator } from './simulators/UtilsSimulator.js'; import * as contractUtils from './utils/address.js'; -======= -import { UtilsSimulator } from './simulators/UtilsSimulator'; -import * as contractUtils from './utils/address'; ->>>>>>> b6f5215 (Add pausable (#22)) const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); @@ -14,11 +9,8 @@ const SOME_CONTRACT = const OTHER_CONTRACT = contractUtils.createEitherTestContractAddress('OTHER_CONTRACT'); -<<<<<<< HEAD const EMPTY_STRING = ''; -======= ->>>>>>> b6f5215 (Add pausable (#22)) let contract: UtilsSimulator; describe('Utils', () => { @@ -27,19 +19,14 @@ describe('Utils', () => { describe('isKeyOrAddressZero', () => { it('should return zero for the zero address', () => { expect(contract.isKeyOrAddressZero(contractUtils.ZERO_KEY)).toBe(true); -<<<<<<< HEAD expect(contract.isKeyOrAddressZero(contractUtils.ZERO_ADDRESS)).toBe( true, ); -======= - expect(contract.isKeyOrAddressZero(contractUtils.ZERO_ADDRESS)).toBe(true); ->>>>>>> b6f5215 (Add pausable (#22)) }); it('should not return zero for nonzero addresses', () => { expect(contract.isKeyOrAddressZero(Z_SOME_KEY)).toBe(false); expect(contract.isKeyOrAddressZero(SOME_CONTRACT)).toBe(false); -<<<<<<< HEAD }); }); @@ -104,56 +91,6 @@ describe('Utils', () => { describe('emptyString', () => { it('should return the empty string', () => { expect(contract.emptyString()).toBe(EMPTY_STRING); -======= ->>>>>>> b6f5215 (Add pausable (#22)) - }); - }); - - describe('isKeyOrAddressEqual', () => { - it('should return true for two matching pubkeys', () => { - expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_SOME_KEY)).toBe(true); - }); - - it('should return true for two matching contract addresses', () => { - expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, SOME_CONTRACT)).toBe( - true, - ); - }); - - it('should return false for two different pubkeys', () => { - expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, Z_OTHER_KEY)).toBe(false); - }); - - it('should return false for two different contract addresses', () => { - expect(contract.isKeyOrAddressEqual(SOME_CONTRACT, OTHER_CONTRACT)).toBe( - false, - ); - }); - - it('should return false for two different address types', () => { - expect(contract.isKeyOrAddressEqual(Z_SOME_KEY, SOME_CONTRACT)).toBe( - false, - ); - }); - }); - - describe('isKeyZero', () => { - it('should return zero for the zero address', () => { - expect(contract.isKeyZero(contractUtils.ZERO_KEY.left)).toBe(true); - }); - - it('should not return zero for nonzero addresses', () => { - expect(contract.isKeyZero(Z_SOME_KEY.left)).toBe(false); - }); - }); - - describe('isContractAddress', () => { - it('should return true if ContractAddress', () => { - expect(contract.isContractAddress(SOME_CONTRACT)).toBe(true); - }); - - it('should return false ZswapCoinPublicKey', () => { - expect(contract.isContractAddress(Z_SOME_KEY)).toBe(false); }); }); }); diff --git a/contracts/utils/src/test/utils/test.ts b/contracts/utils/src/test/utils/test.ts index d467e572..9fd2d4f6 100644 --- a/contracts/utils/src/test/utils/test.ts +++ b/contracts/utils/src/test/utils/test.ts @@ -6,7 +6,7 @@ import { QueryContext, emptyZswapLocalState, } from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types/test'; +import type { IContractSimulator } from '../types/test.js'; /** * Constructs a `CircuitContext` from the given state and sender information. diff --git a/contracts/utils/src/witnesses/MockInitializable.compact b/contracts/utils/src/witnesses/MockInitializable.compact deleted file mode 100644 index d670f6d9..00000000 --- a/contracts/utils/src/witnesses/MockInitializable.compact +++ /dev/null @@ -1,14 +0,0 @@ -pragma language_version >= 0.14.0; - -import CompactStandardLibrary; -import Initializable prefix Initializable_; - -export { Initializable_state, Initializable_STATE }; - -export circuit initialize(): [] { - return Initializable_initialize(); -} - -export circuit isInitialized(): Boolean { - return Initializable_isInitialized(); -} diff --git a/docs/package.json b/docs/package.json index 2b54a42a..02410b35 100644 --- a/docs/package.json +++ b/docs/package.json @@ -12,4 +12,4 @@ "devDependencies": { "@openzeppelin/docs-utils": "^0.1.5" } -} \ No newline at end of file +} diff --git a/package.json b/package.json index c6ee2f02..da56058b 100644 --- a/package.json +++ b/package.json @@ -34,4 +34,4 @@ "typescript": "^5.2.2", "vitest": "^3.1.3" } -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index f904025d..61c189aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -420,6 +420,7 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/non-fungible-token@workspace:contracts/nonFungibleToken" dependencies: + "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:22.14.0" ts-node: "npm:^10.9.2" @@ -432,6 +433,7 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-midnight/utils@workspace:contracts/utils" dependencies: + "@biomejs/biome": "npm:1.9.4" "@openzeppelin-midnight/compact": "workspace:^" "@types/node": "npm:22.14.0" ts-node: "npm:^10.9.2" @@ -657,13 +659,6 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:^1.0.0": - version: 1.0.8 - resolution: "@types/estree@npm:1.0.8" - checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099 - languageName: node - linkType: hard - "@types/node@npm:22.14.0": version: 22.14.0 resolution: "@types/node@npm:22.14.0" @@ -1078,13 +1073,6 @@ __metadata: languageName: node linkType: hard -"emoji-regex@npm:^10.3.0": - version: 10.4.0 - resolution: "emoji-regex@npm:10.4.0" - checksum: 10/76bb92c5bcf0b6980d37e535156231e4a9d0aa6ab3b9f5eabf7690231d5aa5d5b8e516f36e6804cbdd0f1c23dfef2a60c40ab7bb8aedd890584281a565b97c50 - languageName: node - linkType: hard - "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -1492,20 +1480,6 @@ __metadata: languageName: node linkType: hard -"is-unicode-supported@npm:^1.3.0": - version: 1.3.0 - resolution: "is-unicode-supported@npm:1.3.0" - checksum: 10/20a1fc161afafaf49243551a5ac33b6c4cf0bbcce369fcd8f2951fbdd000c30698ce320de3ee6830497310a8f41880f8066d440aa3eb0a853e2aa4836dd89abc - languageName: node - linkType: hard - -"is-unicode-supported@npm:^2.0.0": - version: 2.1.0 - resolution: "is-unicode-supported@npm:2.1.0" - checksum: 10/f254e3da6b0ab1a57a94f7273a7798dd35d1d45b227759f600d0fa9d5649f9c07fa8d3c8a6360b0e376adf916d151ec24fc9a50c5295c58bae7ca54a76a063f9 - languageName: node - linkType: hard - "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -2350,10 +2324,12 @@ __metadata: languageName: node linkType: hard -"tinyrainbow@npm:^2.0.0": - version: 2.0.0 - resolution: "tinyrainbow@npm:2.0.0" - checksum: 10/94d4e16246972614a5601eeb169ba94f1d49752426312d3cf8cc4f2cc663a2e354ffc653aa4de4eebccbf9eeebdd0caef52d1150271fdfde65d7ae7f3dcb9eb5 +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: "npm:^7.0.0" + checksum: 10/10dda13571e1f5ad37546827e9b6d4252d2e0bc176c24a101252153ef435d83696e2557fe128c4678e4e78f5f01e83711c703eef9814eb12dab028580d45980a languageName: node linkType: hard