{"id":21936165,"url":"https://github.com/learnweb3dao/access-private-data","last_synced_at":"2025-07-30T09:37:23.515Z","repository":{"id":37939713,"uuid":"451743891","full_name":"LearnWeb3DAO/Access-Private-Data","owner":"LearnWeb3DAO","description":null,"archived":false,"fork":false,"pushed_at":"2022-08-31T13:00:27.000Z","size":166,"stargazers_count":0,"open_issues_count":0,"forks_count":6,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-29T14:51:11.670Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LearnWeb3DAO.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-01-25T05:13:51.000Z","updated_at":"2022-09-25T16:20:18.000Z","dependencies_parsed_at":"2023-01-16T15:45:26.321Z","dependency_job_id":null,"html_url":"https://github.com/LearnWeb3DAO/Access-Private-Data","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LearnWeb3DAO%2FAccess-Private-Data","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LearnWeb3DAO%2FAccess-Private-Data/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LearnWeb3DAO%2FAccess-Private-Data/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LearnWeb3DAO%2FAccess-Private-Data/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LearnWeb3DAO","download_url":"https://codeload.github.com/LearnWeb3DAO/Access-Private-Data/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250237798,"owners_count":21397399,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-29T01:13:26.050Z","updated_at":"2025-04-22T11:52:32.190Z","avatar_url":"https://github.com/LearnWeb3DAO.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Accessing `private` data\n\nWhen we start writing smart contracts and come across visibility modifiers like `public`, `private`, etc. we may think that if you want some variable's value to be readable by the public you need to declare it `public`, and that `private` variables cannot be read by anyone but the smart contract itself.\n\nBut, Ethereum is a public blockchain. So what does `private` data even mean?\n\nIn this level, we will see how you can actually read `private` variable values from any smart contract, and also clarify what `private` actually stands for - which is definitely not private data!\n\nLets go 🚀\n\n---\n\n## What does `private` mean?\n\nFunction (and variable) visibility modifiers only affect the visibility of the function - and do not prevent access to their values. We know that `public` functions are those which can be called both externally by users and smart contracts, and also by the smart contract itself.\n\nSimilarly, `internal` functions are those which can only be called by the smart contract itself, and outside users and smart contracts cannot call those functions. `external` functions are the opposite, where they can only be called by external users and smart contracts, but not the smart contract that has the function itself.\n\n`private`, similarly, just affects who can call that function. `private` and `internal` behave mostly similarly, except the fact that `internal` functions are also callable by derived contracts, whereas `private` functions are not.\n\n---\n\nSo for example, if `Contract A` has a function `f()` which is marked `internal`, a second `Contract B` which inherits `Contract A` like\n\n```\ncontract B is A {\n  ...\n}\n```\n\ncan still call `f()`.\n\nHowever, if `Contract A` has a function `g()` which is marked `private`, `Contract B` cannot call `g()` even if it inherits from `A`.\n\nThe same is true for variables, as variables are basically just functions. `private` variables can only be accessed and modified by the smart contract itself, not even derived contracts. However, this does not mean that external parties cannot read the value.\n\n\u003cQuiz questionId=\"d3d1b7dc-7129-4155-93a1-51a29342eead\" /\u003e\n\n## BUIDL\n\nWe will build a simple contract, along with a Hardhat Test, to demonstrate this. Our contract will attempt to store data in `private` variables hoping that nobody will be able to read it's value.\n\nThe contract will take in `password` and `username` in its constructor and will store them in private variables.\n\nUser will somehow be able to access those private variables.\n\n### Concepts\n\nTo understand how this works, recall from the Ethereum Storage and Execution level that variables in Solidity are stored in 32 byte (256 bit) storage slots, and that data is stored sequentially in these storage slots based on the order in which these variables are declared.\n\nStorage is also optimized such that if a bunch of variables can fit in one slot, they are put in the same slot. This is called variable packing, and we will learn more about this later.\n\n\u003e Note\n All of these commands should work smoothly . \n If you are on windows and face Errors Like `Cannot read properties of null (reading 'pickAlgorithm')`\n Try Clearing the NPM cache using `npm cache clear --force`.\n---\n\n- To set up a Hardhat project, Open up a terminal and execute these commands\n\n  ```bash\n  npm init --yes\n  npm install --save-dev hardhat\n  ```\n  \n- If you are on a Windows machine, please do this extra step and install these libraries as well :)\n\n  ```bash\n  npm install --save-dev @nomicfoundation/hardhat-toolbox @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers\n  ```\n  \n- In the same directory where you installed Hardhat run:\n\n  ```bash\n  npx hardhat\n  ```\n\n  - Select `Create a basic sample project`\n  - Press enter for the already specified `Hardhat Project root`\n  - Press enter for the question on if you want to add a `.gitignore`\n  - Press enter for `Do you want to install this sample project's dependencies with npm (@nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers)?`\n\nNow you have a hardhat project ready to go!\n\nLet's start by creating a `Login.sol` file inside the `contracts` folder. Add the following lines of code to your file\n\n```solidity\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ncontract Login {\n\n    // Private variables\n    // Each bytes32 variable would occupy one slot\n    // because bytes32 variable has 256 bits(32*8)\n    // which is the size of one slot\n\n    // Slot 0\n    bytes32 private username;\n    // Slot 1\n    bytes32 private password;\n\n    constructor(bytes32  _username, bytes32  _password) {\n        username = _username;\n        password = _password;\n    }\n}\n```\n\nSince both declared variables are `bytes32` variables, we know that each variable takes up exactly one storage slot. Since the order matters, we know that `username` will take up `Slot 0` and `password` will take up `Slot 1`.\n\n\u003cQuiz questionId=\"cb47ac8b-33e3-4efa-9819-8639e88484b2\" /\u003e\n\nTherefore, instead of attempting to read these variable values by calling the contract, which is not possible, we can just access the storage slots directly. Since Ethereum is a public blockchain, all nodes have access to all the state.\n\nLet's write a Hardhat Test to demonstrate this functionality.\n\n---\n\nCreate a new file `attack.js` inside the `test` folder and add the following lines of code\n\n```javascript\nconst { ethers } = require(\"hardhat\");\nconst { expect } = require(\"chai\");\n\ndescribe(\"Attack\", function () {\n  it(\"Should be able to read the private variables password and username\", async function () {\n    // Deploy the login contract\n    const loginFactory = await ethers.getContractFactory(\"Login\");\n\n    // To save space, we would convert the string to bytes32 array\n    const usernameBytes = ethers.utils.formatBytes32String(\"test\");\n    const passwordBytes = ethers.utils.formatBytes32String(\"password\");\n\n    const loginContract = await loginFactory.deploy(\n      usernameBytes,\n      passwordBytes\n    );\n    await loginContract.deployed();\n\n    // Get the storage at storage slot 0,1\n    const slot0Bytes = await ethers.provider.getStorageAt(\n      loginContract.address,\n      0\n    );\n    const slot1Bytes = await ethers.provider.getStorageAt(\n      loginContract.address,\n      1\n    );\n\n    // We are able to extract the values of the private variables\n    expect(ethers.utils.parseBytes32String(slot0Bytes)).to.equal(\"test\");\n    expect(ethers.utils.parseBytes32String(slot1Bytes)).to.equal(\"password\");\n  });\n});\n```\n\nIn this test, we first create `usernameBytes` and `passwordBytes`, which are `bytes32` versions of a short string to behave as our username and password. We then deploy the `Login` contract with those values.\n\nAfter the contract is deployed, we use `provider.getStorageAt` to read storage slot values at `loginContract.address` for slots 0 and 1 directly, and extract the byte values from it.\n\nThen, we can compare the retrieved values - `slot0Bytes` against `usernameBytes` and `slot1Bytes` against `passwordBytes` to ensure they are, in fact, equal.\n\nIf the tests pass, it means we were successfully able to read the values of the private variables directly without needing to call functions on the contract at all.\n\nFinally, lets run this test and see if it works. On your terminal type:\n\n```bash\nnpx hardhat test\n```\n\nThe tests should pass. Wow, we could actually read the password!\n\n## Prevention\n\nNEVER store private information on a public blockchain. No other way around it.\n\n\u003cQuiz questionId=\"3dbb32ec-4b6e-4bc6-9f3d-91aa3132664a\" /\u003e\n\n\u003cSubmitQuiz /\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flearnweb3dao%2Faccess-private-data","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flearnweb3dao%2Faccess-private-data","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flearnweb3dao%2Faccess-private-data/lists"}