L1 Settlement
Since applications built with protokit will in most cases operate as a zk-rollup, one integral part of that security model is the process of “settlement”.
Settlement is the process of validating the integrity and correctness of the off-chain computation, proven to be valid via the so-called “Settlement Proof”, by posting that proof on a underlying blockchain, often called the Layer-1 (L1) of baselayer. In settlement, the entirety of the proofs generated by executing transactions on the protokit appchain are merged and bundled into one Mina transaction. After that transaction is included in a Mina block and verified by the whole Mina network, all transactions that occured on the L2 can be considered valid and final.
Trustless bridging between the L1 and L2 is also possible through settlement. More on that in Bridging
Settlement in protokit
The starter-kit already configures settlement out-of-the-box, you can enable it via the SETTLEMENT_ENABLED and other env-variables
The settlement functionality is implemented via a set of modules shipped with the protokit sequencer.
Configuring settlement to protokit is very easy, it consists of three components:
- Settlement Contract (zkapp): Is the smart contract code that verifies settlement
- Base Layer: Configured module that tells the sequencer what the settlement layer is and where to find it
- Settlement Module: The central module coordinating the process from finished BlockProof to the same ending up finalized on the L1
Supported Networks
Protokit supports multiple types of networks: Local, Lightnet and Remote.
- Local runs in-memory and mainly used for unit-testing zkapps - its of little use for the protokit app development cycle.
- Lightnet is a locally run mina node that has faster block times, instant finality and pre-funded accounts and is therefore very useful for testing protokit apps and their settlement and bridging capability. It features all features a normal node has, including graphql APIs and an archive node
- Remote networks are used for devnet and mainnet, which are used for deploying testnets and launching your app on mainnet.
Setup
Modules configuration
You can configure them by appending the configuration of your AppChain like:
// TODO Update
import { Balances } from "./guest-book/myBalance";
import { SettlementContractModule } from "@proto-kit/protocol";
import { SettlementModule, MinaBaseLayer, SettlementProvingTask, AppChain } from "@proto-kit/sequencer";
const appChain = AppChain.with(
{
Balances,
},
{
SettlementContractModule: SettlementContractModule.with({}),
},
{
BaseLayer: MinaBaseLayer,
SettlementModule: SettlementModule,
},
{
SettlementProvingTask,
}
);Its important to notice that settlement will automatically use the BaseLayer that’s configured, so make sure you configure the right one.
Network configuration
Configuring a network is done via the BaseLayer module (in this case MinaBaseLayer).
appchain.configure({
...
Sequencer: {
BaseLayer: {
network: {
type: "local"
}
}
}
}TODO
Key configuration
TODO
Deploying L1 contracts
Use the SettlementModule.deploy function.
This function takes in the private keys of the contracts and resolves successfully if all deployment
transactions have been sent and included in the L1.
const settlementModule = appChain.sequencer.resolveOrFail(
"SettlementModule",
SettlementModule
);
await settlementModule.deploy(
settlementContractPrivateKey,
dispatchContractPrivateKey,
bridgeContractPrivateKey,
);
console.log("Settlement successful")That’s it, now start your appchain and settlement should automatically commence in the interval you configured.
One of the most important requirements is that a Balances runtime module has to exist in the configured runtime.
L1 Deposits and Withdrawals go through that module (see configuration below).
Additionally, the Withdrawals runtime module has to be set.
As with the default Balances module, it has no callable functions by default, therefore relies on user code to be called.
The responsibilities of the services configured above is the following:
| Service | Responsibilities |
|---|---|
| SettlementContractModule | Contains the provable L1 zkapp contracts that facilitate the settlement and trustless bridging |
| BaseLayer | Service to communicate with the Mina node endpoints (send transactions, query account states, …) |
| OutgoingMessageQueue | Observes the protokit runtime and dispatches L1 transactions that process the withdrawals on Mina |
| SettlementModule | Uses all of the above to coordinate the settlement process and ensure the correct proof orchestration |
Configuring the settlement
appChain.configurePartial({
Runtime: {
Balances: {},
Withdrawals: {},
},
Protocol: {
SettlementContract: {},
BridgeContract: {},
DispatchContract: {
incomingMessagesMethods: {
// Used for bridging, see those docs
},
},
},
Sequencer: {
OutgoingMessageQueue: {},
BaseLayer: {
network: {
// In the case of lightnet
type: "lightnet", // types "local" and "remote" are also available
graphql: "http://127.0.0.1:8080/graphql",
archive: "http://127.0.0.1:8282",
accountManager: "http://127.0.0.1:8181",
},
},
SettlementModule: {
feepayer: sequencerKey,
},
}
})This configuration tells the protokit sequencer what methods are used for deposit and withdrawal calls and what StateMap outgoing withdrawals are put into.
Note:
withdrawalMethodPath: Has to be a user-invokable runtime method (i.e.@runtimeMethod()) that under the hood calls theWithdrawal.withdraw()function provided by the Withdrawal module.incomingMessagesMethods.deposit: Has to be a runtime method annotated with@runtimeMessage(). This allows it to be invoked through the L1 contract’s dispatched deposit.