Proxy RPC API
The proxy RPC API is the main component that enables privacy in the ZKsync Stack.
In a standard rollup, there is a standard RPC API that provides full access to transaction data for users. The proxy RPC is an additional layer in between end users and the chain's standard RPC API. The proxy layer enables authentication of requests to the standard RPC.
Access to the standard RPC should remain private. We highly recommend implementing a secure firewall around the standard RPC API. Only the proxy RPC API endpoint should be publicly shared.
Setting up the Proxy
After your ecosystem and validium chain are setup, you can initialize the Proxy API.
To initialize the Proxy API service, open a new terminal in your ecosystem folder and run:
zkstack private-rpc init
You can select the default options for the prompts.
This command will generate two files:
- A private proxy
docker-compose
file at/chains/prividium_chain/configs/private-proxy-docker-compose.yml
- An example permissions config file at
/chains/prividium_chain/configs/private-rpc-permissions.yaml
.
Next, you can start the Proxy API service with:
zkstack private-rpc run
The Proxy API should now be running at port 4041
.
Upgrading the Proxy
To upgrade your proxy API to the latest version:
- Run
zkstackup
to upgrade your version ofzkstack
. - Update the
zksync-era
repo in the ecosystem folder. - Delete the
private-rpc
Docker container. - Re-run the
zkstack private-rpc init
command. This command will update the chain'sprivate-proxy-docker-compose.yml
file, but won't change theprivate-rpc-permissions.yaml
config. - Start the server with
zkstack private-rpc run
.
Configuring the Proxy
In the generated docker compose file, you can configure the environment variables as needed.
The service is configured through six key environment variables:
CORS_ORIGIN
: sets the web-origin domain that the API will accept requests from. It defaults to the local port where the block explorer runs. It can also be an array of domains separated by a comma.CREATE_TOKEN_SECRET
: the shared secret used to verify clients requesting to create new access tokens.PERMISSIONS_YAML_PATH
: points to the YAML file that lists the access rules enforced by the proxy.DATABASE_URL
: points to the chain's PostgreSQL database.PORT
: the port where the proxy itself listens (4041
by default).TARGET_RPC
: the standard internal RPC API endpoint the proxy forwards validated requests to.
Configuring Access
To configure access to different smart contracts on your chain, Prividium uses a simple YAML file. Edits to the permissions file only require a restart of the Proxy service to be applied.
You can see what an example configuration file looks like below:
groups:
- name: 'group1'
members:
- '0xeaAFbF6Fc352B0598e34f4F282939720D9cf0f59'
- name: 'group2'
members:
- '0x71e6dDfE9074786Fd8e986C53f78D25450d614D5'
contracts:
- address: '0xBE06E7e23AA92a6B0523A0E7cBb43690De7af8DB'
methods:
- signature: 'function number() (uint256)'
read:
type: 'public'
write:
type: 'public'
- signature: 'function owner() (address)'
read:
type: 'group'
groups: ['group1']
write:
type: 'group'
groups: ['group1']
- signature: 'function fromGroup1Address() public'
read:
type: 'group'
groups: ['group1']
write:
type: 'group'
groups: ['group1']
- signature: 'function fromGroup2Address() public'
read:
type: 'group'
groups: ['group2']
write:
type: 'group'
groups: ['group2']
- signature: 'function hiTo(address) public'
read:
type: 'checkArgument'
argIndex: 0
write:
type: 'checkArgument'
argIndex: 0
The permissions config file at
/chains/prividium_chain/configs/private-rpc-permissions.yaml
can be edited based on what access you want end users to have.
There are two sections in the permissions file:
groups
: Logical collections of users or addresses sharing the same permissions.contracts
: Specific contracts or methods that a group is allowed to access.
Groups Access
You can define hard-coded groups of administrative addresses in the groups
section.
A group consists of a name and a list of member addresses.
After defining a group,
the group name can be used in the contracts
section to grant the entire group certain access.
Contracts Access
The contracts
section defines the level of access available to specific contracts and their functions.
If a contract is not included here, or a function not defined,
it can only be accessed via the standard RPC API.
Note that contracts can only be deployed via the standard RPC API.
Defining Methods
For a given contract address, the methods
field defines the contract functions that can be called.
The function signature is used to identify functions and define rules for them. The format should the same signature as the canonical signature defined in Solidity ABI.
To generate a list of your contract's functions in this format,
you can use the formatAbiItem
method from abitype
,
as shown in the example script below.
import ABI_JSON from '../artifacts-zk/contracts/erc20/MyERC20Token.sol/MyERC20Token.json';
import { type AbiFunction, formatAbiItem } from 'abitype';
async function main() {
const { abi } = ABI_JSON;
abi.forEach((item) => {
if (item.type === 'function') {
const signature = formatAbiItem(item as AbiFunction);
console.log(signature);
}
});
}
Method Access
For each function, you can define a rule for read
and write
regardless of whether the function itself is a pure function.
For each rule within a read
or write
section,
you must choose a type
.
The types available out-of-the-box include:
public
: anyone can call this function.closed
: no one can call this function (default).group
: only the specified groups can call this.checkArgument
: the specified argument index must match the function caller's address.oneOf
: allows you to define more than one rule type. It functions as anOR
operator; if at least one condition is met, access is granted.
In addition to these rules,
there is a universal rule applied
so that users can only see transactions where
their address is equal to the msg.sender
.
You can fully customize the types and their access logic by editing the zksync-era/private-rpc/src/permissions/yaml-parser.ts
file.
The example implementation showcases one approach, but it can be easily modified to accommodate unique workflows or compliance requirements.