diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9da4667a..fc4ada33 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -108,36 +108,3 @@ jobs: run: | echo "## Proposal simulator tests result" >> $GITHUB_STEP_SUMMARY echo "✅ Passed" >> $GITHUB_STEP_SUMMARY - - type-check-test: - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v3" - with: - submodules: "recursive" - - - name: "Install Foundry" - uses: "foundry-rs/foundry-toolchain@v1" - - - name: "Show the Foundry config" - run: "forge config" - - - name: "Install Node.js" - uses: "actions/setup-node@v3" - with: - node-version: "lts/*" - - - name: "Install the Node.js dependencies" - run: "cd typescript/ && npm install && cd ../ && npm install ts-node" - - - name: "Build the contracts and print their size" - run: "forge build --sizes" - - - name: "Run typecheck tests" - run: "forge test --mc TypeCheck --ffi --fork-url sepolia" - - - name: "Add test summary" - run: | - echo "## Type check tests result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY diff --git a/.gitignore b/.gitignore index ac225a4b..ec283bc9 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,3 @@ node_modules/ lcov.info -# typescript -typescript/node_modules/ - -typescript/package-lock.json \ No newline at end of file diff --git a/README.md b/README.md index 3ba9482c..fa1212b5 100644 --- a/README.md +++ b/README.md @@ -50,76 +50,6 @@ Choose a model that fits your needs: Create scripts and/or tests. Check [Guides](docs/guides/multisig-proposal.md) and [Integration Tests](docs/testing/integration-tests.md). -### Type Checking - -Type checking allows verification of deployed bytecode on any contracts with the bytecode present in local artifacts. With this feature, developer `A` can easily deploy some contracts, and developer `B` can verify `A`'s deployments by simply running the type checking script. Additionaly, `A` can also use this feature to verify their own deployments. `A` can take the following steps: - -- Follow the steps 1 to 3 on [Proposal Simulation](#proposal-simulation) section -- Add the deployed contracts to `Addresses.json`. -- Create a `TypeCheckAddresses.json` file following the instructions provided in [type-check.md](docs/guides/type-check.md). -- Enter `lib/forge-proposal-simulator/typescript` directory and install npm packages. - -```bash -cd lib/forge-proposal-simulator/typescript && npm i -``` - -- Change directory again to the root repo - -```bash -cd ../../../ -``` - -- Add below environment variables to `.env`. - -``` -ADDRESSES_PATH # Path to addresses.json file -TYPE_CHECK_ADDRESSES_PATH # Path to typeCheckAddresses.json file -``` - -Example: - -``` -TYPE_CHECK_ADDRESSES_PATH=addresses/TypeCheckAddresses.json -ADDRESSES_PATH=addresses/Addresses.json -ARTIFACT_PATH=out/ -``` - -- Make sure to allow read access to `Addresses.json`, `TypeCheckAddresses.json` and `artifact` folder inside of `foundry.toml`. - -```toml -[profile.default] - -fs_permissions = [{ access = "read", path = "./"}] -``` - -- Run the following command on root repo to type check all contracts added in `TypeCheckAddresses.json`. - -```bash -forge script lib/forge-proposal-simulator/script/TypeCheck.s.sol:TypeCheck --ffi --fork-url -``` - -### Type checking on Example contracts FPS - -#### Step 1: Set environment variables - -``` -TYPE_CHECK_ADDRESSES_PATH="addresses/TypeCheckAddresses.json" -ADDRESSES_PATH="addresses/Addresses.json" -LIB_PATH="" -``` - -#### Step 2: Run script to test type checking - -```bash -forge script script/TypeCheck.s.sol:TypeCheck --ffi --fork-url sepolia -``` - -You can also run type checking through inline environment variables if not already set in .env - -```bash -TYPE_CHECK_ADDRESSES_PATH="addresses/TypeCheckAddresses.json" ADDRESSES_PATH="addresses/Addresses.json" ARTIFACT_PATH="out/" LIB_PATH="" forge script script/TypeCheck.s.sol:TypeCheck --ffi --fork-url sepolia -``` - ## Contribute There are many ways you can participate and help build the next version of FPS. Check out the [contribution guide](CONTRIBUTING.md)! diff --git a/addresses/Addresses.json b/addresses/Addresses.json index 8c9658d0..3de7f7f3 100644 --- a/addresses/Addresses.json +++ b/addresses/Addresses.json @@ -95,18 +95,6 @@ "isContract": true, "name": "BRAVO_VAULT_TOKEN" }, - { - "addr": "0x293cad26033577eb68137603a34d2dbfd05104d8", - "chainId": 11155111, - "name": "ExampleTypeCheck", - "isContract": true - }, - { - "addr": "0x9D7A602541230B2bA04D9aA542fad73B8aaBA4ED", - "chainId": 11155111, - "name": "ExampleTypeCheck_02", - "isContract": true - }, { "addr": "0x5a0Aae59D09fccBdDb6C6CcEB07B7279367C3d2A", "chainId": 1, diff --git a/addresses/AddressesIncorrect.json b/addresses/AddressesIncorrect.json deleted file mode 100644 index 0bd8dcac..00000000 --- a/addresses/AddressesIncorrect.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "addr": "0x8FB9B57A1Af027ca5f4EF262280fFF880c22D371", - "chainId": 11155111, - "name": "ExampleTypeCheck", - "isContract": true - }, - { - "addr": "0xf875fEcfF122927E53C3b07F4258C690b026004b", - "chainId": 11155111, - "name": "ExampleTypeCheck_02", - "isContract": true - } -] diff --git a/addresses/TypeCheckAddresses.json b/addresses/TypeCheckAddresses.json deleted file mode 100644 index 17cb610a..00000000 --- a/addresses/TypeCheckAddresses.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "name": "ExampleTypeCheck", - "constructorArgs": "[[\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", \"0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5000000000000000000000000\", [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2, [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2]]], [\"Arg1\", \"Arg2\"], [2, 3], [[\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2, [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2]], [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2, [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2]]]]", - "artifactPath": "out/ExampleTypeCheck.sol/ExampleTypeCheck.json" - }, - { - "name": "ExampleTypeCheck_02", - "constructorArgs": "[[[1, 2], [3, 4]], [[[1, 2]], [[3, 4]]], [[[[[1, 2]], [[3, 4]]]], [[[[5, 6]], [[7, 8]]]]], [[\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\"], [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\"]]]", - "artifactPath": "out/ExampleTypeCheck_02.sol/ExampleTypeCheck_02.json" - } -] diff --git a/addresses/TypeCheckAddressesIncorrect.json b/addresses/TypeCheckAddressesIncorrect.json deleted file mode 100644 index e3058696..00000000 --- a/addresses/TypeCheckAddressesIncorrect.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "name": "ExampleTypeCheck", - "constructorArgs": "[[\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", \"0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5000000000000000000000000\", [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2, [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2]]], [\"Arg1\", \"Arg2\"], [2, 3], [[\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2, [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2]], [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2, [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2]]]]", - "artifactPath": "out/ExampleTypeCheck_02.sol/ExampleTypeCheck_02.json" - }, - { - "name": "ExampleTypeCheck_02", - "constructorArgs": "[[[1, 2], [3, 4]], [[[1, 2]], [[3, 4]]], [[[[[1, 2]], [[3, 4]]]], [[[[5, 6]], [[7, 8]]]]], [[\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\"], [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\"]]]", - "artifactPath": "out/ExampleTypeCheck.sol/ExampleTypeCheck.json" - } -] diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index c453d70d..831de804 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -27,12 +27,6 @@ - [Integration Tests](testing/integration-tests.md) -## Type checking - -- [Introduction](type-check/introduction.md) -- [Type Check Example](type-check/example.md) -- [TypeCheckAddresses.json](type-check/type-check.md) - ## Github Actions - [Printing Calldata on Pull Requests](actions/print-calldata.md) diff --git a/docs/type-check/example.md b/docs/type-check/example.md deleted file mode 100644 index 6f2352ae..00000000 --- a/docs/type-check/example.md +++ /dev/null @@ -1,108 +0,0 @@ -# Example Type Check - -After adding FPS to the project dependencies and following the [setup guide](./introduction.md#setting-up), it's time to go through an example contract to understand how type checking works. - -## Example Contracts - -The [folder](../../src/type-check) includes contracts used in the guide mentioned below for demonstration purposes. Examples include [ExampleTypeCheck.sol](../../src/type-check/ExampleTypeCheck.sol) and [ExampleTypeCheck_02.sol](../../src/type-check/ExampleTypeCheck_02.sol). - -Add the file `ExampleTypeCheck.sol` to the `src` folder of the root repository: - -```solidity -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity ^0.8.0; - -contract ExampleTypeCheck { - struct StructC { - string varC1; - uint256 varC2; - } - - struct StructB { - bytes varB1; - uint256 varB2; - StructC structC; - } - struct StructA { - address varA1; - bytes32 varA2; - StructB structB; - } - - constructor( - StructA memory structA, - string[] memory arg1, - uint256[] memory arg2, - StructB[] memory structb - ) {} - - function encode( - StructA memory structA, - string[] memory arg1, - uint256[] memory arg2, - StructB[] memory structb - ) external pure returns (bytes memory) { - return abi.encode(structA, arg1, arg2, structb); - } -} -``` - -The contract constructor arguments appear complex for this example; luckily, we already have the constructor arguments ready. - -In the file `TypeCheckAddresses.json`, which has already been created in the setup, add another object in the JSON file for the above contract: - -```json -{ - "name": "ExampleTypeCheck", - "constructorArgs": "[[\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", \"0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5000000000000000000000000\", [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2, [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2]]], [\"Arg1\", \"Arg2\"], [2, 3], [[\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2, [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2]], [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2, [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2]]]]", - "artifactPath": "out/ExampleTypeCheck.sol/ExampleTypeCheck.json" -} -``` - -Note: The default artifact folder is `out`. If it is different in your project in `foundry.toml`, change the above artifact path accordingly. - -Now, add the following object to `Addresses.json`: - -```json -{ - "addr": "0x293cad26033577eb68137603a34d2dbfd05104d8", - "chainId": 11155111, - "name": "ExampleTypeCheck", - "isContract": true -} -``` - -The above contract is already deployed on the Sepolia testnet, and it will check that the correct contract is deployed by verifying the bytecode of the Sepolia contract with the local bytecode of the `ExampleTypeCheck` contract. - -Check that npm packages are already installed and environment variables are added. If they aren't, see the [setup guide](./introduction.md#setting-up) for instructions. - -Make sure to allow read access to `Addresses.json`, `TypeCheckAddresses.json`, and the `artifact` folder inside `foundry.toml`. - -```toml -[profile.default] - -fs_permissions = [{ access = "read", path = "./"}] -``` - -Run the following command on the root repo to type-check all contracts added in `TypeCheckAddresses.json`: - -```bash -forge script lib/forge-proposal-simulator/script/TypeCheck.s.sol:TypeCheck --ffi --fork-url "https://ethereum-sepolia-rpc.publicnode.com" -``` - -The script should run successfully, confirming that the deployed contract is correct. The command should create the following output, as shown below: - -```txt -Script ran successfully. - -== Logs == - -Contract: ExampleTypeCheck - Encoded contructor args : - 0x000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000036000000000000000000000000095222290dd7278aa3ddd389cc1e1d165cc4bafe595222290dd7278aa3ddd389cc1e1d165cc4bafe500000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001495222290dd7278aa3ddd389cc1e1d165cc4bafe500000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002a3078393532323232393044443732373841613344646433383943633145316431363543433442416665350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000044172673100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000441726732000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001495222290dd7278aa3ddd389cc1e1d165cc4bafe500000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002a307839353232323239304444373237384161334464643338394363314531643136354343344241666535000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001495222290dd7278aa3ddd389cc1e1d165cc4bafe500000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002a30783935323232323930444437323738416133446464333839436331453164313635434334424166653500000000000000000000000000000000000000000000 - Local deployed bytecode: - 0x608060405234801561001057600080fd5b506004361061002b5760003560e01c806325b3caa214610030575b600080fd5b61004361003e3660046103f6565b610059565b6040516100509190610540565b60405180910390f35b606084848484604051602001610072949392919061063d565b6040516020818303038152906040529050949350505050565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156100c4576100c461008b565b60405290565b6040805190810167ffffffffffffffff811182821017156100c4576100c461008b565b604051601f8201601f1916810167ffffffffffffffff811182821017156101165761011661008b565b604052919050565b600067ffffffffffffffff8311156101385761013861008b565b61014b601f8401601f19166020016100ed565b905082815283838301111561015f57600080fd5b828260208301376000602084830101529392505050565b600082601f83011261018757600080fd5b6101968383356020850161011e565b9392505050565b6000606082840312156101af57600080fd5b6101b76100a1565b9050813567ffffffffffffffff808211156101d157600080fd5b818401915084601f8301126101e557600080fd5b6101f48583356020850161011e565b835260208401356020840152604084013591508082111561021457600080fd5b908301906040828603121561022857600080fd5b6102306100ca565b82358281111561023f57600080fd5b61024b87828601610176565b8252506020830135602082015280604085015250505092915050565b600067ffffffffffffffff8211156102815761028161008b565b5060051b60200190565b600082601f83011261029c57600080fd5b813560206102b16102ac83610267565b6100ed565b82815260059290921b840181019181810190868411156102d057600080fd5b8286015b8481101561031057803567ffffffffffffffff8111156102f45760008081fd5b6103028986838b0101610176565b8452509183019183016102d4565b509695505050505050565b600082601f83011261032c57600080fd5b8135602061033c6102ac83610267565b82815260059290921b8401810191818101908684111561035b57600080fd5b8286015b84811015610310578035835291830191830161035f565b600082601f83011261038757600080fd5b813560206103976102ac83610267565b82815260059290921b840181019181810190868411156103b657600080fd5b8286015b8481101561031057803567ffffffffffffffff8111156103da5760008081fd5b6103e88986838b010161019d565b8452509183019183016103ba565b6000806000806080858703121561040c57600080fd5b843567ffffffffffffffff8082111561042457600080fd5b908601906060828903121561043857600080fd5b6104406100a1565b82356001600160a01b038116811461045757600080fd5b81526020838101359082015260408301358281111561047557600080fd5b6104818a82860161019d565b6040830152509550602087013591508082111561049d57600080fd5b6104a98883890161028b565b945060408701359150808211156104bf57600080fd5b6104cb8883890161031b565b935060608701359150808211156104e157600080fd5b506104ee87828801610376565b91505092959194509250565b6000815180845260005b8181101561052057602081850181015186830182015201610504565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061019660208301846104fa565b600081516060845261056860608501826104fa565b9050602083015160208501526040830151848203604086015280516040835261059460408401826104fa565b6020928301519390920192909252949350505050565b600081518084526020808501945080840160005b838110156105da578151875295820195908201906001016105be565b509495945050505050565b600082825180855260208086019550808260051b84010181860160005b8481101561063057601f1986840301895261061e838351610553565b98840198925090830190600101610602565b5090979650505050505050565b608080825285516001600160a01b03169082015260208086015160a08301526040860151606060c08401526000919061067960e0850182610553565b9050838103828501528087518083528383019150838160051b840101848a0160005b838110156106c957601f198684030185526106b78383516104fa565b9487019492509086019060010161069b565b505086810360408801526106dd818a6105aa565b94505050505082810360608401526106f581856105e5565b97965050505050505056fe - Deployed bytecode: - 0x608060405234801561001057600080fd5b506004361061002b5760003560e01c806325b3caa214610030575b600080fd5b61004361003e3660046103f6565b610059565b6040516100509190610540565b60405180910390f35b606084848484604051602001610072949392919061063d565b6040516020818303038152906040529050949350505050565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156100c4576100c461008b565b60405290565b6040805190810167ffffffffffffffff811182821017156100c4576100c461008b565b604051601f8201601f1916810167ffffffffffffffff811182821017156101165761011661008b565b604052919050565b600067ffffffffffffffff8311156101385761013861008b565b61014b601f8401601f19166020016100ed565b905082815283838301111561015f57600080fd5b828260208301376000602084830101529392505050565b600082601f83011261018757600080fd5b6101968383356020850161011e565b9392505050565b6000606082840312156101af57600080fd5b6101b76100a1565b9050813567ffffffffffffffff808211156101d157600080fd5b818401915084601f8301126101e557600080fd5b6101f48583356020850161011e565b835260208401356020840152604084013591508082111561021457600080fd5b908301906040828603121561022857600080fd5b6102306100ca565b82358281111561023f57600080fd5b61024b87828601610176565b8252506020830135602082015280604085015250505092915050565b600067ffffffffffffffff8211156102815761028161008b565b5060051b60200190565b600082601f83011261029c57600080fd5b813560206102b16102ac83610267565b6100ed565b82815260059290921b840181019181810190868411156102d057600080fd5b8286015b8481101561031057803567ffffffffffffffff8111156102f45760008081fd5b6103028986838b0101610176565b8452509183019183016102d4565b509695505050505050565b600082601f83011261032c57600080fd5b8135602061033c6102ac83610267565b82815260059290921b8401810191818101908684111561035b57600080fd5b8286015b84811015610310578035835291830191830161035f565b600082601f83011261038757600080fd5b813560206103976102ac83610267565b82815260059290921b840181019181810190868411156103b657600080fd5b8286015b8481101561031057803567ffffffffffffffff8111156103da5760008081fd5b6103e88986838b010161019d565b8452509183019183016103ba565b6000806000806080858703121561040c57600080fd5b843567ffffffffffffffff8082111561042457600080fd5b908601906060828903121561043857600080fd5b6104406100a1565b82356001600160a01b038116811461045757600080fd5b81526020838101359082015260408301358281111561047557600080fd5b6104818a82860161019d565b6040830152509550602087013591508082111561049d57600080fd5b6104a98883890161028b565b945060408701359150808211156104bf57600080fd5b6104cb8883890161031b565b935060608701359150808211156104e157600080fd5b506104ee87828801610376565b91505092959194509250565b6000815180845260005b8181101561052057602081850181015186830182015201610504565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061019660208301846104fa565b600081516060845261056860608501826104fa565b9050602083015160208501526040830151848203604086015280516040835261059460408401826104fa565b6020928301519390920192909252949350505050565b600081518084526020808501945080840160005b838110156105da578151875295820195908201906001016105be565b509495945050505050565b600082825180855260208086019550808260051b84010181860160005b8481101561063057601f1986840301895261061e838351610553565b98840198925090830190600101610602565b5090979650505050505050565b608080825285516001600160a01b03169082015260208086015160a08301526040860151606060c08401526000919061067960e0850182610553565b9050838103828501528087518083528383019150838160051b840101848a0160005b838110156106c957601f198684030185526106b78383516104fa565b9487019492509086019060010161069b565b505086810360408801526106dd818a6105aa565b94505050505082810360608401526106f581856105e5565b97965050505050505056fe -``` diff --git a/docs/type-check/introduction.md b/docs/type-check/introduction.md deleted file mode 100644 index ca307a42..00000000 --- a/docs/type-check/introduction.md +++ /dev/null @@ -1,71 +0,0 @@ -# Type Checking - -Type checking enables the validation of deployed bytecode against local artifacts, ensuring accuracy. This facilitates a team of developers to verify each other's deployments with the type checking script. A developer can intiate verification of his team member's bytecode by deploying the contract locally through Foundry, then compare their generated bytecode with the already on-chain version. He can use it to verify his own deployements as well. By leveraging type checking, a team of developers can efficiently validate contracts, enhancing transparency and security in their Solidity smart contract development workflows. - -Let's explore a hypothetical scenario where a team is going to deploy to Ethereum mainnet. One developer deploys an old version of contracts because he forgot to pull the latest contracts. The older version that he has deployed has a critical bug in a single line of code. Other team members go to etherscan to verify the source code looks correct, however, they might miss checking whether the latest bug fix is deployed or not. Instead, if they use the type checking script they will be able to verify the deployment automatically without having to look at and compare each and every line of code. - -## Setting Up - -### Step 1: Add Dependency - -Add `forge-proposal-simulator` to your project using Forge: - -```sh -forge install https://github.com/solidity-labs-io/forge-proposal-simulator.git -``` - -### Step 2: Remapping - -Update your `remappings.txt` to include: - -```sh -echo @forge-proposal-simulator=lib/forge-proposal-simulator/ >> remappings.txt -``` - -### Step 3: Addresses File - -Create a JSON file following the structure defined in [Addresses](../overview/architecture/addresses.md). Keeping the addresses file in a separate folder for example `./addresses/addresses.json` is recommended. Add all contracts to `Addresses.json`. - -### Step 4: TypeCheckAddresses File - -Create a `TypeCheckAddresses.json` file following the instructions provided in [type-check.md](./type-check.md). - -### Step 5: Install npm packages - -Enter the `lib/forge-proposal-simulator/typescript` directory and install npm packages. - -```bash -cd lib/forge-proposal-simulator/typescript && npm i -``` - -Change the directory again to the root repo. - -```bash -cd ../../../ -``` - -### Step 6: Add Environment Variables - -Add the below environment variables to `.env`. - -``` -ADDRESSES_PATH # Path to addresses.json file -TYPE_CHECK_ADDRESSES_PATH # Path to typeCheckAddresses.json file -``` - -Example: - -``` -TYPE_CHECK_ADDRESSES_PATH=addresses/TypeCheckAddresses.json -ADDRESSES_PATH=addresses/Addresses.json -``` - -### Step 7: File Read Access - -Make sure to allow read access to `Addresses.json`, `TypeCheckAddresses.json`, and the `artifact` folder inside of `foundry.toml`. - -```toml -[profile.default] - -fs_permissions = [{ access = "read", path = "./"}] -``` diff --git a/docs/type-check/type-check.md b/docs/type-check/type-check.md deleted file mode 100644 index f2086e23..00000000 --- a/docs/type-check/type-check.md +++ /dev/null @@ -1,87 +0,0 @@ -# Type check Addresses - -## Overview - -The `TypeCheckAddresses.json` file is a JSON file used for verifying the bytecode of already deployed contracts on any chain. This file contains a list of objects, where each object stores the `name`, `constructorArgs`, and `artifactPath` for all the contracts that needs to be type checked. The `name` should be the same as the `name` in `Addresses.json` as it links both JSONs together. The `constructorArgs` should be in comma-separated array format. For `address`, `bytes`, and `string`, double quotes should be used. Tuples, on the other hand, are passed like arrays `[]`. Additionally, each `"` in JSON is escaped using `\` since it is a special character in the JSON file. - -## Structure - -ExampleTypeCheck.sol - -```solidity -pragma solidity ^0.8.0; - -contract ExampleTypeCheck { - struct StructC { - string varC1; - uint256 varC2; - } - - struct StructB { - bytes varB1; - uint256 varB2; - StructC structC; - } - struct StructA { - address varA1; - bytes32 varA2; - StructB structB; - } - - constructor( - StructA memory structA, - string[] memory arg1, - uint256[] memory arg2, - StructB[] memory structb - ) {} - - function encode( - StructA memory structA, - string[] memory arg1, - uint256[] memory arg2, - StructB[] memory structb - ) external pure returns (bytes memory) { - return abi.encode(structA, arg1, arg2, structb); - } -} -``` - -ExampleTypeCheck_02.sol - -```solidity -pragma solidity ^0.8.0; - -contract ExampleTypeCheck_02 { - struct StructA { - uint256[] varA1; - } - - struct StructB { - StructA[] varB1; - } - - constructor( - uint256[][] memory, - StructA[] memory, - StructB[] memory, - address[][] memory - ) {} -} -``` - -TypeCheckAddresses.json for above two contract. - -```json -[ - { - "name": "ExampleTypeCheck", - "constructorArgs": "[[\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", \"0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5000000000000000000000000\", [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2, [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2]]], [\"Arg1\", \"Arg2\"], [2, 3], [[\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2, [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2]], [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2, [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\", 2]]]]", - "artifactPath": "out/ExampleTypeCheck.sol/ExampleTypeCheck.json" - }, - { - "name": "ExampleTypeCheck_02", - "constructorArgs": "[[[1, 2], [3, 4]], [[[1, 2]], [[3, 4]]], [[[[[1, 2]], [[3, 4]]]], [[[[5, 6]], [[7, 8]]]]], [[\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\"], [\"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\"]]]", - "artifactPath": "out/ExampleTypeCheck_02.sol/ExampleTypeCheck_02.json" - } -] -``` diff --git a/remappings.txt b/remappings.txt index 7974fb11..7210cbab 100644 --- a/remappings.txt +++ b/remappings.txt @@ -2,7 +2,6 @@ @test=test/ @proposals/=src/proposals/ @interface/=src/interface/ -@type-check/=src/type-check/ @addresses/=addresses/ @utils/=utils/ @examples/=examples/ diff --git a/script/DeployExampleTypeCheck.s.sol b/script/DeployExampleTypeCheck.s.sol deleted file mode 100644 index 526b81e8..00000000 --- a/script/DeployExampleTypeCheck.s.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity =0.8.19; - -import "forge-std/Script.sol"; -import "../src/type-check/ExampleTypeCheck.sol"; - -contract DeployExampleTypeCheck is Script { - function run() external { - vm.startBroadcast(); - - ExampleTypeCheck.StructC memory structC = ExampleTypeCheck.StructC({ - varC1: "0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5", - varC2: 2 - }); - - ExampleTypeCheck.StructB memory structB = ExampleTypeCheck.StructB({ - varB1: hex"95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5", - varB2: 2, - structC: structC - }); - - ExampleTypeCheck.StructA memory structA = ExampleTypeCheck.StructA({ - varA1: 0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5, - varA2: hex"95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5", - structB: structB - }); - - string[] memory stringArg = new string[](2); - stringArg[0] = "Arg1"; - stringArg[1] = "Arg2"; - - uint256[] memory uintArg = new uint256[](2); - uintArg[0] = 2; - uintArg[1] = 3; - - ExampleTypeCheck.StructB[] - memory structBArrayArg = new ExampleTypeCheck.StructB[](2); - - structBArrayArg[0] = ExampleTypeCheck.StructB({ - varB1: hex"95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5", - varB2: 2, - structC: structC - }); - - structBArrayArg[1] = ExampleTypeCheck.StructB({ - varB1: hex"95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5", - varB2: 2, - structC: structC - }); - - new ExampleTypeCheck(structA, stringArg, uintArg, structBArrayArg); - - vm.stopBroadcast(); - } -} diff --git a/script/TypeCheck.s.sol b/script/TypeCheck.s.sol deleted file mode 100644 index 890bceb1..00000000 --- a/script/TypeCheck.s.sol +++ /dev/null @@ -1,16 +0,0 @@ -pragma solidity ^0.8.0; - -import "forge-std/Script.sol"; -import {TypeChecker} from "@type-check/TypeChecker.sol"; - -contract TypeCheck is Script { - string public ADDRESSES_PATH = vm.envString("ADDRESSES_PATH"); - string public TYPE_CHECK_ADDRESSES_PATH = - vm.envString("TYPE_CHECK_ADDRESSES_PATH"); - string public LIB_PATH = - vm.envOr("LIB_PATH", string("lib/forge-proposal-simulator/")); - - function run() public virtual { - new TypeChecker(ADDRESSES_PATH, TYPE_CHECK_ADDRESSES_PATH, LIB_PATH); - } -} diff --git a/src/type-check/ExampleTypeCheck.sol b/src/type-check/ExampleTypeCheck.sol deleted file mode 100644 index f58a3f5f..00000000 --- a/src/type-check/ExampleTypeCheck.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity =0.8.19; - -contract ExampleTypeCheck { - struct StructC { - string varC1; - uint256 varC2; - } - - struct StructB { - bytes varB1; - uint256 varB2; - StructC structC; - } - - struct StructA { - address varA1; - bytes32 varA2; - StructB structB; - } - - constructor( - StructA memory structA, - string[] memory arg1, - uint256[] memory arg2, - StructB[] memory structb - ) {} - - function encode( - StructA memory structA, - string[] memory arg1, - uint256[] memory arg2, - StructB[] memory structb - ) external pure returns (bytes memory) { - return abi.encode(structA, arg1, arg2, structb); - } -} diff --git a/src/type-check/ExampleTypeCheck_02.sol b/src/type-check/ExampleTypeCheck_02.sol deleted file mode 100644 index 554a9cd9..00000000 --- a/src/type-check/ExampleTypeCheck_02.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity =0.8.19; - -contract ExampleTypeCheck_02 { - struct StructA { - uint256[] varA1; - } - - struct StructB { - StructA[] varB1; - } - - constructor( - uint256[][] memory, - StructA[] memory, - StructB[] memory, - address[][] memory - ) {} -} diff --git a/src/type-check/TypeChecker.sol b/src/type-check/TypeChecker.sol deleted file mode 100644 index aef80023..00000000 --- a/src/type-check/TypeChecker.sol +++ /dev/null @@ -1,143 +0,0 @@ -pragma solidity ^0.8.0; - -import {Addresses} from "@addresses/Addresses.sol"; -import {Test} from "@forge-std/Test.sol"; -import "@forge-std/console.sol"; - -contract TypeChecker is Test { - Addresses public addresses; - - bytes public constant IPFS = hex"69706673"; - - bytes public constant SOLC = hex"736f6c63"; - - struct SavedTypeCheckAddresses { - /// Artifact path - string artifactPath; - /// Constructor argument for the contract to be checked - string constructorArgs; - /// name of contract to store - string name; - } - - constructor( - string memory addressesPath, - string memory typeCheckAddressesPath, - string memory libPath - ) { - addresses = new Addresses(addressesPath); - - string memory addressesData = string( - abi.encodePacked(vm.readFile(typeCheckAddressesPath)) - ); - - bytes memory parsedJson = vm.parseJson(addressesData); - - SavedTypeCheckAddresses[] memory savedTypeCheckAddresses = abi.decode( - parsedJson, - (SavedTypeCheckAddresses[]) - ); - - for (uint256 i = 0; i < savedTypeCheckAddresses.length; i++) { - string[] memory commands = new string[](5); - - /// note to future self, ffi absolutely flips out if you try to set env vars - commands[0] = "npx"; - commands[1] = "ts-node"; - commands[2] = string( - abi.encodePacked(libPath, "typescript/encode.ts") - ); - commands[3] = savedTypeCheckAddresses[i].constructorArgs; - commands[4] = savedTypeCheckAddresses[i].artifactPath; - - console.log("\nContract:", savedTypeCheckAddresses[i].name); - - bytes memory encodedConstructorArgs = vm.ffi(commands); - console.log("Encoded contructor args :"); - emit log_bytes(encodedConstructorArgs); - - address contractAddress = deployCode( - savedTypeCheckAddresses[i].artifactPath, - encodedConstructorArgs - ); - - bytes memory deployedBytecode = addresses - .getAddress(savedTypeCheckAddresses[i].name) - .code; - - bytes memory localDeployedBytecode = contractAddress.code; - - if ( - matchPattern(localDeployedBytecode, IPFS) && - matchPattern(localDeployedBytecode, SOLC) - ) { - deployedBytecode = _removeMetadata(deployedBytecode); - - localDeployedBytecode = _removeMetadata(localDeployedBytecode); - } - - console.log("Local deployed bytecode: "); - emit log_bytes(localDeployedBytecode); - console.log("Deployed bytecode: "); - emit log_bytes(deployedBytecode); - - require( - keccak256(deployedBytecode) == keccak256(localDeployedBytecode), - "Deployed bytecode not matched" - ); - } - } - - function _removeMetadata( - bytes memory data - ) internal pure returns (bytes memory) { - require(data.length >= 2, "Byte array must have at least 2 bytes"); - - // Convert last two bytes to uint16 - uint16 metadataSize = uint16(uint8(data[data.length - 2])) * - 256 + - uint16(uint8(data[data.length - 1])); - - require( - data.length >= metadataSize, - "Number of bytes to remove exceeds length of byte array" - ); - - // Subtracting 2 to remove last 2 bytes that stores the metadata size - uint256 trimmedSize = data.length - metadataSize - 2; - - // Create a new byte array with the updated length - bytes memory trimmedData = new bytes(trimmedSize); - - // Copy data except the last metadata bytes - for (uint256 i = 0; i < trimmedSize; i++) { - trimmedData[i] = data[i]; - } - - return trimmedData; - } - - function matchPattern( - bytes memory data, - bytes memory pattern - ) public pure returns (bool) { - require( - data.length >= pattern.length, - "Data length is less than pattern length" - ); - - for (uint256 i = 0; i <= data.length - pattern.length; i++) { - bool isMatch = true; - for (uint256 j = 0; j < pattern.length; j++) { - if (data[i + j] != pattern[j]) { - isMatch = false; - break; - } - } - if (isMatch) { - return true; - } - } - return false; - } -} diff --git a/test/TypeCheck.t.sol b/test/TypeCheck.t.sol deleted file mode 100644 index fe0c713c..00000000 --- a/test/TypeCheck.t.sol +++ /dev/null @@ -1,46 +0,0 @@ -pragma solidity ^0.8.0; - -import {TypeChecker} from "@type-check/TypeChecker.sol"; -import {Test} from "forge-std/Test.sol"; - -contract TypeCheck is Test { - string public constant ADDRESSES_PATH = "addresses/Addresses.json"; - string public constant TYPE_CHECK_ADDRESSES_PATH = - "addresses/TypeCheckAddresses.json"; - string public constant TYPE_CHECK_ADDRESSES_PATH_INCORRECT = - "addresses/TypeCheckAddressesIncorrect.json"; - string public constant ADDRESSES_PATH_INCORRECT = - "addresses/AddressesIncorrect.json"; - string public constant LIB_PATH = ""; - TypeChecker public typechecker; - - function test_typeCheck() public { - typechecker = new TypeChecker( - ADDRESSES_PATH, - TYPE_CHECK_ADDRESSES_PATH, - LIB_PATH - ); - } - - // Artifact path is incorrect in TypeCheckAddresses.json - function test_typeCheckIncorrectArtifact() public { - vm.expectRevert( - "StdCheats deployCode(string,bytes): Deployment failed." - ); - typechecker = new TypeChecker( - ADDRESSES_PATH, - TYPE_CHECK_ADDRESSES_PATH_INCORRECT, - LIB_PATH - ); - } - - // Deployed bytecode is incorrect - function test_typeCheckIncorrectByteCode() public { - vm.expectRevert("Deployed bytecode not matched"); - typechecker = new TypeChecker( - ADDRESSES_PATH_INCORRECT, - TYPE_CHECK_ADDRESSES_PATH, - LIB_PATH - ); - } -} diff --git a/typescript/encode.ts b/typescript/encode.ts deleted file mode 100644 index 335f2214..00000000 --- a/typescript/encode.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { ethers } from "ethers"; -import * as fs from "fs"; - -function extractABI(artifactPath: string): any { - try { - const jsonData = fs.readFileSync(artifactPath, "utf-8"); - const contractJSON = JSON.parse(jsonData); - - return contractJSON.abi; - } catch (error) { - throw new Error(`ABI not found on path.`); - } -} - -// Recursive function to traverse and generate type array -function traverseInputs(inputs: any, depth: number): any { - if (depth == 0) { - return inputs.map((input: any) => { - if (input.type === "tuple[]") { - return `tuple(${traverseInputs( - input.components, - depth + 1, - )})[]`; - } - if (input.type === "tuple") { - return `tuple(${traverseInputs(input.components, depth + 1)})`; - } else { - return input.type; - } - }); - } - return inputs - .map((input: any) => { - if (input.type === "tuple[]") { - return `tuple(${traverseInputs( - input.components, - depth + 1, - )})[]`; - } else if (input.type === "tuple") { - return `tuple(${traverseInputs(input.components, depth + 1)})`; - } else { - return input.type; - } - }) - .join(", "); -} - -// Function to generate type array based on the ABI format -function generateTypeArray(abi: any[]): string[] { - const constructorAbi = abi.find((item) => item.type === "constructor"); - if (!constructorAbi) { - throw new Error(`Constructor not found in ABI.`); - } - - const inputs = constructorAbi.inputs; - - const typeArray: string[] = traverseInputs(inputs, 0); - return typeArray; -} - -// Function to encode data based on the ABI format -function encodeData(abi: any[], constructorInputs: any[]): string { - const types = generateTypeArray(abi); - - return ethers.utils.defaultAbiCoder.encode(types, constructorInputs); -} - -// Gets command line arguments -const args = process.argv; - -// Removes '\' from command line args -const cleanedArg = args[2].replace(/\\/g, ""); - -const constructorInputs = JSON.parse(cleanedArg); - -const artifactPath = args[3]; - -const abi = extractABI(artifactPath); - -// Encode the constructor inputs -const encodedData = encodeData(abi, constructorInputs); -process.stdout.write(encodedData); diff --git a/typescript/package.json b/typescript/package.json deleted file mode 100644 index a008ec6a..00000000 --- a/typescript/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "encode-args-ts", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "dependencies": { - "ethers": "5.7.2" - } -} diff --git a/typescript/tsconfig.json b/typescript/tsconfig.json deleted file mode 100644 index 1d30ba8e..00000000 --- a/typescript/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2015", - "moduleResolution": "node", - "module": "commonjs", - "resolveJsonModule": true, - "esModuleInterop": true - }, - "include": ["./**/*.ts"] -}