commit b6a52cf88d85cafa0a4fe4917e14c18136ab21c6 Author: Theo Date: Wed Nov 22 23:43:23 2023 +0100 Initial commit diff --git a/.env.bat.example b/.env.bat.example new file mode 100644 index 0000000..25246cf --- /dev/null +++ b/.env.bat.example @@ -0,0 +1,3 @@ +set MAINNET_RPC_URL= +set PRIVATE_KEY= +set ETHERSCAN_KEY= \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ecd9cc1 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +MAINNET_RPC_URL= +PRIVATE_KEY= +ETHERSCAN_KEY= \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..db72ca3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +.env +.env.bat + +# Node modules +node_modules/ +package-lock.json + +# yarn +yarn.lock + +# VScode files +.vscode \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..888d42d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/forge-std"] + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std diff --git a/README.md b/README.md new file mode 100644 index 0000000..e63c749 --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# Proposal title + +### Changes / effect description + +- 1 +- 2 +- ... + +### Requirements + +- Rust ([Need only for Windows](https://doc.rust-lang.org/cargo/getting-started/installation.html)) +- Foundryup ([Windows](https://github.com/altugbakan/foundryup-windows), [Linux](https://book.getfoundry.sh/getting-started/installation)) +- Node 14 or higher ([Windows](https://github.com/coreybutler/nvm-windows), [Linux](https://github.com/nvm-sh/nvm)) + +### Installation + +```text +git clone --recurse-submodules +cd +npm install +npm run init +``` + +### Testing + +```text +npm run test:windows +``` + +or + +```text +npm run test:linux +``` + +##### Test with gas + +```text +npm run test:gas:windows +``` + +or + +```text +npm run test:gas:linux +``` diff --git a/data/.gitkeep b/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/foundry.toml b/foundry.toml new file mode 100644 index 0000000..28a09c4 --- /dev/null +++ b/foundry.toml @@ -0,0 +1,26 @@ +[profile.default] +# General +src = 'src' +out = 'out' +libs = ["node_modules", "lib"] + +# Compiler +auto_detect_solc = true +via_ir = true +optimizer = true +optimizer_runs = 200 +auto_detect_remappings = true + +# Network +chain_id = 1 + +# Tests +verbosity = 3 + +[rpc_endpoints] +mainnet = "${MAINNET_RPC_URL}" + +[fmt] +line_length = 140 +number_underscore = 'thousands' +bracket_spacing = true \ No newline at end of file diff --git a/lib/.gitkeep b/lib/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json new file mode 100644 index 0000000..40c7245 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "forge-proposal-template", + "version": "1.0.0", + "repository": "https://git.tornado.ws/Theo/forge-proposal-template", + "author": "Theo", + "license": "MIT", + "type": "module", + "private": false, + "scripts": { + "init": "cd lib && git clone --recurse-submodules https://github.com/foundry-rs/forge-std", + "test:windows": ".\\.env.bat && forge test", + "test:linux": ". .env && forge test", + "test:gas:windows": ".\\.env.bat && forge test --gas-report", + "test:gas:linux": ". .env && forge test --gas-report" + }, + "dependencies": { + "@ensdomains/ens-contracts": "^0.0.21", + "@openzeppelin/contracts": "^4.9.0", + "@openzeppelin/upgrades-core": "^1.26.2" + }, + "optionalDependencies": { + "@gnosis.pm/ido-contracts": "^0.5.0", + "@gnosis.pm/safe-contracts": "1.3.0" + }, + "devDependencies": { + "ts-node": "^10.9.1", + "typescript": "^5.1.6" + } +} diff --git a/remappings.txt b/remappings.txt new file mode 100644 index 0000000..91d487a --- /dev/null +++ b/remappings.txt @@ -0,0 +1,11 @@ +@root/=src/ +@interfaces/=src/interfaces +@proprietary/=src/proprietary +@forge-std/=lib/forge-std/src/ + +@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/ +@openzeppelin/upgrades/=node_modules/@openzeppelin/upgrades-core/ +@ens/contracts/=node_modules/@ensdomains/ens-contracts/contracts/ +@gnosis/contracts/=node_modules/@gnosis.pm/safe-contracts/contracts/ +@gnosis/ido-contracts/=node_modules/@gnosis.pm/ido-contracts/contracts/ +@torn-token/=node_modules/torn-token/ diff --git a/scripts/utils.ts b/scripts/utils.ts new file mode 100644 index 0000000..ff27200 --- /dev/null +++ b/scripts/utils.ts @@ -0,0 +1,34 @@ +type NodeVarObject = { [key: string]: string }; +type NodeVarArray = [string, string]; + +const solidityCodePadding = " ".repeat(8); +const pad = (decl: string, padding: string = solidityCodePadding) => padding + decl + "\n"; + +class DeclCalculator { + public constructor( + private declType: string, + private padding: string = solidityCodePadding, + private transformator: Function = ( + () => (x: any) => + x + )(), + private variableNameChanger: Function = ( + () => (x: any) => + x + )() + ) {} + + private displayVariableName(varObj: NodeVarObject) { + return Object.keys(varObj)[0]; + } + + public calculateDecl = (varInfo: NodeVarObject | NodeVarArray, type: string = "bytes32") => { + const solidityVariableName = this.variableNameChanger(Array.isArray(varInfo) ? varInfo[0] : this.displayVariableName(varInfo)); + const solidityVariableValue = this.transformator(Array.isArray(varInfo) ? varInfo[1] : Object.values(varInfo)[0]); + const solidityDeclaration = `${this.declType || type} ${solidityVariableName} = ${solidityVariableValue};`; + + return pad(solidityDeclaration, this.padding); + }; +} + +export { DeclCalculator }; diff --git a/src/ExampleProposal.sol b/src/ExampleProposal.sol new file mode 100644 index 0000000..68fd33d --- /dev/null +++ b/src/ExampleProposal.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { IGovernance } from "@interfaces/IGovernance.sol"; + +contract ExampleProposal { + function executeProposal() public { + /* ... */ + } +} diff --git a/src/interfaces/IGnosisSafe.sol b/src/interfaces/IGnosisSafe.sol new file mode 100644 index 0000000..5a96277 --- /dev/null +++ b/src/interfaces/IGnosisSafe.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +interface IGnosisSafe { + enum Operation { + Call, + DelegateCall + } + + function NAME() external view returns (string memory); + + function VERSION() external view returns (string memory); + + function nonce() external view returns (uint256); + + function domainSeparator() external view returns (bytes32); + + function signedMessages(bytes32) external view returns (uint256); + + function approvedHashes(address, bytes32) external view returns (uint256); + + function setup( + address[] calldata _owners, + uint256 _threshold, + address to, + bytes calldata data, + address fallbackHandler, + address paymentToken, + uint256 payment, + address payable paymentReceiver + ) external; + + function execTransaction( + address to, + uint256 value, + bytes calldata data, + Operation operation, + uint256 safeTxGas, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address payable refundReceiver, + bytes calldata signatures + ) external returns (bool success); + + function requiredTxGas(address to, uint256 value, bytes calldata data, Operation operation) + external + returns (uint256); + + function approveHash(bytes32 hashToApprove) external; + + function signMessage(bytes calldata _data) external; + + function isValidSignature(bytes calldata _data, bytes calldata _signature) external returns (bytes4); + + function getMessageHash(bytes memory message) external view returns (bytes32); + + function encodeTransactionData( + address to, + uint256 value, + bytes memory data, + Operation operation, + uint256 safeTxGas, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address refundReceiver, + uint256 _nonce + ) external view returns (bytes memory); + + function getTransactionHash( + address to, + uint256 value, + bytes memory data, + Operation operation, + uint256 safeTxGas, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address refundReceiver, + uint256 _nonce + ) external view returns (bytes32); +} diff --git a/src/interfaces/IGovernance.sol b/src/interfaces/IGovernance.sol new file mode 100644 index 0000000..87b124d --- /dev/null +++ b/src/interfaces/IGovernance.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +enum ProposalState { + Pending, + Active, + Defeated, + Timelocked, + AwaitingExecution, + Executed, + Expired +} + +struct Proposal { + // Creator of the proposal + address proposer; + // target addresses for the call to be made + address target; + // The block at which voting begins + uint256 startTime; + // The block at which voting ends: votes must be cast prior to this block + uint256 endTime; + // Current number of votes in favor of this proposal + uint256 forVotes; + // Current number of votes in opposition to this proposal + uint256 againstVotes; + // Flag marking whether the proposal has been executed + bool executed; + // Flag marking whether the proposal voting time has been extended + // Voting time can be extended once, if the proposal outcome has changed during CLOSING_PERIOD + bool extended; +} + +interface IGovernance { + function initialized() external view returns (bool); + function initializing() external view returns (bool); + function EXECUTION_DELAY() external view returns (uint256); + function EXECUTION_EXPIRATION() external view returns (uint256); + function QUORUM_VOTES() external view returns (uint256); + function PROPOSAL_THRESHOLD() external view returns (uint256); + function VOTING_DELAY() external view returns (uint256); + function VOTING_PERIOD() external view returns (uint256); + function CLOSING_PERIOD() external view returns (uint256); + function VOTE_EXTEND_TIME() external view returns (uint256); + function torn() external view returns (address); + function proposals(uint256 index) external view returns (Proposal memory); + function proposalCount() external view returns (uint256); + function lockedBalance(address account) external view returns (uint256); + function propose(address target, string memory description) external returns (uint256); + function castVote(uint256 proposalId, bool support) external; + function lock(address owner, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + function lockWithApproval(uint256 amount) external; + function unlock(uint256 amount) external; + function execute(uint256 proposalId) external payable; + function state(uint256 proposalId) external view returns (ProposalState); +} diff --git a/src/proprietary/TornadoAddresses.sol b/src/proprietary/TornadoAddresses.sol new file mode 100644 index 0000000..7d9e98d --- /dev/null +++ b/src/proprietary/TornadoAddresses.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +contract TornadoAddresses { + address public constant ENSAddress = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e; + address public constant tornTokenAddress = 0x77777FeDdddFfC19Ff86DB637967013e6C6A116C; + address public constant multisigAddress = 0xb04E030140b30C27bcdfaafFFA98C57d80eDa7B4; + address public constant governanceAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce; + address public constant stakingAddress = 0x5B3f656C80E8ddb9ec01Dd9018815576E9238c29; + address public constant relayerRegistryAddress = 0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2; + address public constant feeManagerAddress = 0x5f6c97C6AD7bdd0AE7E0Dd4ca33A4ED3fDabD4D7; + address public constant governanceVaultAddress = 0x2F50508a8a3D323B91336FA3eA6ae50E55f32185; +} diff --git a/test/ExampleProposal.t.sol b/test/ExampleProposal.t.sol new file mode 100644 index 0000000..9efd7bc --- /dev/null +++ b/test/ExampleProposal.t.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { ProposalUtils } from "./utils/ProposalUtils.sol"; +import { ExampleProposal } from "@root/ExampleProposal.sol"; + +import { console2 } from "@forge-std/console2.sol"; + +contract TestExampleProposal is ProposalUtils { + modifier executeCurrentProposalBefore() { + createAndExecuteProposal(); + _; + } + + function createAndExecuteProposal() public { + address proposalAddress = address(new ExampleProposal()); /* your proposal initialization */ + + proposeAndExecute(proposalAddress); + } + + /* your tests */ + + function testProposal() public executeCurrentProposalBefore { } +} diff --git a/test/utils/Mock.sol b/test/utils/Mock.sol new file mode 100644 index 0000000..f3d0c00 --- /dev/null +++ b/test/utils/Mock.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { IGovernance } from "@interfaces/IGovernance.sol"; + +contract Mock { + // Developer address with 22 staked TORN + address public constant TEST_REAL_ADDRESS_WITH_BALANCE = 0x9Ff3C1Bea9ffB56a78824FE29f457F066257DD58; + address public constant TEST_RELAYER_ADDRESS = 0x30F96AEF199B399B722F8819c9b0723016CEAe6C; // moon-relayer.eth (just for testing) + + // Address and private key to test staking, Governance lock and rewards accruals + address public constant TEST_STAKER_ADDRESS = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; + uint256 public constant TEST_STAKER_PRIVATE_KEY = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80; + + // Test account to create proposal and vote for it + address public constant TEST_ADDRESS_ONE = 0x118251976c65AFAf291f5255450ddb5b6A4d8B88; + uint256 public constant TEST_PRIVATE_KEY_ONE = 0x66ddbd7cbe4a566df405f6ded0b908c669f88cdb1656380c050e3a457bd21df0; +} diff --git a/test/utils/MockProposal.sol b/test/utils/MockProposal.sol new file mode 100644 index 0000000..398e48d --- /dev/null +++ b/test/utils/MockProposal.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { IGovernance } from "@interfaces/IGovernance.sol"; +import { TornadoAddresses } from "@proprietary/TornadoAddresses.sol"; + +import { Test } from "@forge-std/Test.sol"; +import { console2 } from "@forge-std/console2.sol"; + +contract MockProposal is TornadoAddresses, Test { + uint256 public PROPOSAL_VOTING_DURATION; + uint256 public PROPOSAL_LOCKED_DURATION; + uint256 public PROPOSAL_DURATION; + uint256 public PROPOSAL_EXECUTION_MAX_DURATION; + uint256 public PROPOSAL_QOURUM_THRESHOLD; + uint256 public PROPOSAL_VOTE_EXTEND_TIME; + string public constant PROPOSAL_DESCRIPTION = "{title:'Some proposal',description:''}"; + + function _fetchConfiguration() internal { + IGovernance governance = IGovernance(governanceAddress); + + PROPOSAL_LOCKED_DURATION = governance.EXECUTION_DELAY(); + PROPOSAL_EXECUTION_MAX_DURATION = governance.EXECUTION_EXPIRATION(); + PROPOSAL_QOURUM_THRESHOLD = governance.QUORUM_VOTES(); + PROPOSAL_VOTING_DURATION = governance.VOTING_PERIOD(); + PROPOSAL_VOTE_EXTEND_TIME = governance.VOTE_EXTEND_TIME(); + PROPOSAL_DURATION = PROPOSAL_VOTING_DURATION + PROPOSAL_LOCKED_DURATION; + } + + function setUp() public virtual { + // If fork block number unitialized, then set latest + if (block.number == 1) vm.createSelectFork(vm.rpcUrl("mainnet")); + else vm.createSelectFork(vm.rpcUrl("mainnet"), block.number); + + _fetchConfiguration(); + } +} diff --git a/test/utils/ProposalUtils.sol b/test/utils/ProposalUtils.sol new file mode 100644 index 0000000..31b9197 --- /dev/null +++ b/test/utils/ProposalUtils.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { Utils } from "./Utils.sol"; +import { Proposal, IGovernance } from "@interfaces/IGovernance.sol"; + +contract ProposalUtils is Utils { + IGovernance internal governance = IGovernance(governanceAddress); + + function getProposalExecutableTime(uint256 proposalId) internal view returns (uint256) { + Proposal memory proposal = getProposal(proposalId); + return proposal.endTime + PROPOSAL_LOCKED_DURATION + 1 seconds; + } + + function getProposal(uint256 proposalId) internal view returns (Proposal memory) { + return governance.proposals(proposalId); + } + + function hasProposal(uint256 proposalId) internal view returns (bool) { + return governance.proposalCount() >= proposalId; + } + + function waitUntilExecutable(uint256 proposalId) internal { + uint256 proposalExecutableTime = getProposalExecutableTime(proposalId); + require(block.timestamp < proposalExecutableTime + PROPOSAL_EXECUTION_MAX_DURATION, "Too late to execute proposal"); + + vm.warp(proposalExecutableTime); + } + + function proposeAndVote(address proposalAddress) public returns (uint256) { + retrieveAndLockBalance(TEST_PRIVATE_KEY_ONE, TEST_ADDRESS_ONE, PROPOSAL_QOURUM_THRESHOLD + 1 ether); + + /* ----------PROPOSE------------ */ + vm.startPrank(TEST_ADDRESS_ONE); + + uint256 proposalId = governance.propose(proposalAddress, PROPOSAL_DESCRIPTION); + + /* ------------------------------ */ + + // TIME-TRAVEL + vm.warp(block.timestamp + 6 hours); + + /* ------------VOTE-------------- */ + + governance.castVote(proposalId, true); + + vm.stopPrank(); + /* ------------------------------ */ + + return proposalId; + } + + function proposeAndExecute(address proposalAddress) public { + uint256 proposalId = proposeAndVote(proposalAddress); + + waitUntilExecutable(proposalId); + governance.execute(proposalId); + + returnTokensToGovernanceAfterVoting(proposalId); + } + + function returnTokensToGovernanceAfterVoting(uint256 proposalId) public { + uint256 retrievedAmount = PROPOSAL_QOURUM_THRESHOLD + 1 ether; + + uint256 proposalExecutableTime = getProposalExecutableTime(proposalId); + uint256 tokensUnlockTime = proposalExecutableTime + PROPOSAL_VOTE_EXTEND_TIME + PROPOSAL_EXECUTION_MAX_DURATION + 1 seconds; + + if (block.timestamp < tokensUnlockTime) vm.warp(tokensUnlockTime); + + vm.startPrank(TEST_ADDRESS_ONE); + + governance.unlock(retrievedAmount); + IERC20(tornTokenAddress).transfer(governanceAddress, retrievedAmount); + + vm.stopPrank(); + } +} diff --git a/test/utils/Utils.sol b/test/utils/Utils.sol new file mode 100644 index 0000000..51b1acd --- /dev/null +++ b/test/utils/Utils.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; +import { Test } from "@forge-std/Test.sol"; + +import { TornadoAddresses } from "@proprietary/TornadoAddresses.sol"; +import { Mock } from "./Mock.sol"; +import { MockProposal } from "./MockProposal.sol"; +import { IGovernance } from "@interfaces/IGovernance.sol"; + +contract Utils is TornadoAddresses, Test, Mock, MockProposal { + address public constant VERIFIER_ADDRESS = tornTokenAddress; + + bytes32 public constant PERMIT_TYPEHASH = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + bytes32 public constant EIP712_DOMAIN = keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256(bytes("TornadoCash")), + keccak256(bytes("1")), + 1, + VERIFIER_ADDRESS + ) + ); + + uint16 public constant PERMIT_FUNC_SELECTOR = uint16(0x1901); + + function retrieveAndLockBalance(uint256 privateKey, address voter, uint256 amount) public { + uint256 lockTimestamp = block.timestamp + PROPOSAL_DURATION; + uint256 accountNonce = ERC20Permit(tornTokenAddress).nonces(voter); + + bytes32 messageHash = keccak256( + abi.encodePacked( + PERMIT_FUNC_SELECTOR, + EIP712_DOMAIN, + keccak256(abi.encode(PERMIT_TYPEHASH, voter, governanceAddress, amount, accountNonce, lockTimestamp)) + ) + ); + + /* ----------GOVERNANCE------- */ + vm.startPrank(governanceAddress); + IERC20(tornTokenAddress).transfer(voter, amount); + vm.stopPrank(); + /* ----------------------------*/ + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, messageHash); + + /* ----------VOTER------------ */ + vm.startPrank(voter); + IGovernance(governanceAddress).lock(voter, amount, lockTimestamp, v, r, s); + vm.stopPrank(); + /* ----------------------------*/ + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2eb3a35 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,109 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "NodeNext" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + "allowImportingTsExtensions": true /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */, + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + "resolveJsonModule": true /* Enable importing .json files. */, + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./dist" /* Specify an output folder for all emitted files. */, + // "removeComments": true, /* Disable emitting comments. */ + "noEmit": true /* Disable emitting files from a compilation. */, + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + "allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */, + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +}