Fetching Data
Smart contract storage can be used to read from smart contract state variables and to retrieve stored information. This could be anything from user balances, configuration parameters, or complex data structures such as mappings and arrays.
In this guide, we will walk through:
- How smart contract storage works in general.
- Common scenarios where you need to retrieve data from contract storage.
- Step-by-step instructions on how to fetch data, using Solidity and a client library (e.g.,
web3.js
orethers.js
). - Best practices and potential pitfalls.
By the end, you will understand how to confidently and securely fetch data from your peaq-based smart contracts.
Prerequisites
- Understanding of Solidity
- You have a working development environment set up with:
- A Solidity compiler (e.g., via Hardhat, Truffle, or Remix).
- Access to the peaq network’s EVM endpoint (or a local test EVM).
- Using a library like
web3.js
orethers.js
to interact with your deployed contracts. Alternatively, any other JSON-RPC client can be used if you are comfortable with lower-level interactions. - Already have a deployed contract on the peaq network, or you have the means to deploy one during testing.
- Access to contract’s its Application Binary Interface (ABI). This is generally generated automatically when compiling your Solidity smart contract.
Instructions
1. Understanding EVM Contract Storage
In EVM-based networks like peaq, each contract has its own allocated storage. Storage is typically broken down into slots of 256 bits each:
- State Variables store data in these storage slots.
- Mappings are hashed to find their storage slots.
- Arrays and other data structures have their own packing and storage rules.
When writing or reading from storage, gas costs and efficient layout (for writes) can be important. However, retrieving data (a read) is cheaper than storing data (a write). For reads, you can query the node’s state without incurring on-chain transaction costs.
2. Declaring and Storing Data in Solidity
Let’s look at a simple example contract that stores some data:
storedValue
is a publicuint256
. By making it public, Solidity automatically creates a getter functionstoredValue()
that returns the value.balances
is a public mapping fromaddress
touint256
. Likewise,balances(address)
becomes a getter function to read the balance for any given address.
3. Interacting With the Contract to Fetch Data
Using a Script (JavaScript + ethers.js/web3.js)
Below is an example of how to fetch data from storedValue
and balances
using ethers.js
.
Ethers.js Example:
Key Points
- We use the
view
functions (storedValue()
andbalances(address)
) to retrieve data without sending a transaction. - This means there is no cost in terms of gas for these read operations; only the provider’s request/response overhead applies.
Using the Remix IDE
If you prefer a browser-based approach:
- Open Remix IDE.
- Select the “Solidity” environment and load your contract code.
- Compile and Deploy to a peaq network-compatible endpoint (via “Deploy & run transactions” panel).
- After deployment, you will see the contract’s interface in Remix.
- Clicking on
storedValue
will fetch and display the currentstoredValue
. - Providing an address to
balances
will fetch and display the mapping value for that address.
- Clicking on
4. Fetching Custom or Complex Data Types
If you have custom data structures like structs or nested mappings, you can expose them through custom getter functions. For example:
Here, the struct User
is stored in a private mapping. We expose a getUser
function that returns the data in a single call. You can fetch it from your JavaScript code similarly with a function call:
This approach helps keep your contract’s data private while still allowing necessary read-access to data via dedicated functions.
Summary
Fetching data from smart contract storage on the peaq network (or any EVM-compatible network) follows the same paradigm as Ethereum:
- You define state variables in Solidity.
- You expose those variables either with the
public
keyword or dedicated getter functions. - You interact with them through a client library (e.g.,
ethers.js
,web3.js
) or Remix IDE.
Key Takeaways:
- Public Variables: Automatically generate getter functions, convenient for straightforward retrieval.
- View/Pure Functions: Cost no gas when called off-chain, making them ideal for reading data.
- Custom Getter Functions: Useful for complex data structures or additional data processing.
- Security: Ensure that any data you do not want freely accessible remains in private variables, and only expose it through controlled view functions as needed.
With these core principles in mind, you can confidently fetch data from your peaq-based Solidity contracts, enabling rich dApp functionality and user-friendly front-end experiences.