Espresso Network Smart Contracts
Smart contracts for the Espresso Network.
Upgradeable contracts use the frozen inheritance pattern: each new version (e.g. StakeTableV2) inherits from the
previous version, preserving storage layout and ensuring upgrade safety.
Contracts
- EspToken
- EspTokenV2
- FeeContract
- InitializedAt
- LightClient
- LightClientArbitrum
- LightClientArbitrumV2
- LightClientArbitrumV3
- LightClientV2
- LightClientV3
- OpsTimelock
- RewardClaim
- SafeExitTimelock
- StakeTable
- StakeTableV2
Interfaces
Libraries
Contents
- interfaces
- legacy
- libraries
- EspToken
- EspTokenV2
- FeeContract
- InitializedAt
- LightClient
- ArbSys
- LightClientArbitrum
- ArbSys
- LightClientArbitrumV2
- ArbSys
- LightClientArbitrumV3
- LightClientV2
- LightClientV3
- OpsTimelock
- RewardClaim
- SafeExitTimelock
- StakeTable
- StakeTableV2
Contents
ILightClient
Functions
blocksPerEpoch
function blocksPerEpoch() external view returns (uint64);
IPlonkVerifier
Title: The structs and interfaces for a specific flavor of TurboPlonk verifier.
Functions
verify
Verify a single TurboPlonk proofs.
function verify(
VerifyingKey memory verifyingKey,
uint256[] memory publicInput,
PlonkProof memory proof
) external view returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
verifyingKey | VerifyingKey | The Plonk verification key |
publicInput | uint256[] | The public input fields |
proof | PlonkProof | The TurboPlonk proof |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | _ A boolean indicating successful verification, false otherwise |
Structs
PlonkProof
struct PlonkProof {
// the first 5 are 4 inputs and 1 output wire poly commmitments
// i.e., batch_proof.wires_poly_comms_vec.iter()
// wire0 is 32 bytes which is a pointer to BN254.G1Point
BN254.G1Point wire0; // 0x00
BN254.G1Point wire1; // 0x20
BN254.G1Point wire2; // 0x40
BN254.G1Point wire3; // 0x60
BN254.G1Point wire4; // 0x80
// the next one is the product permutation poly commitment
// i.e., batch_proof.prod_perm_poly_comms_vec.iter()
BN254.G1Point prodPerm; // 0xA0
// the next 5 are split quotient poly commmitments
// i.e., batch_proof.split_quot_poly_comms
BN254.G1Point split0; // 0xC0
BN254.G1Point split1; // 0xE0
BN254.G1Point split2; // 0x100
BN254.G1Point split3; // 0x120
BN254.G1Point split4; // 0x140
// witness poly com for aggregated opening at `zeta`
// i.e., batch_proof.opening_proof
BN254.G1Point zeta; // 0x160
// witness poly com for shifted opening at `zeta * \omega`
// i.e., batch_proof.shifted_opening_proof
BN254.G1Point zetaOmega; // 0x180
// wire poly eval at `zeta`
BN254.ScalarField wireEval0; // 0x1A0
BN254.ScalarField wireEval1; // 0x1C0
BN254.ScalarField wireEval2; // 0x1E0
BN254.ScalarField wireEval3; // 0x200
BN254.ScalarField wireEval4; // 0x220
// extended permutation (sigma) poly eval at `zeta`
// last (sigmaEval4) is saved by Maller Optimization
BN254.ScalarField sigmaEval0; // 0x240
BN254.ScalarField sigmaEval1; // 0x260
BN254.ScalarField sigmaEval2; // 0x280
BN254.ScalarField sigmaEval3; // 0x2A0
// product permutation poly eval at `zeta * \omega`
BN254.ScalarField prodPermZetaOmegaEval; // 0x2C0
}
VerifyingKey
struct VerifyingKey {
uint256 domainSize; // 0x00
uint256 numInputs; // 0x20
// commitment to extended perm (sigma) poly
BN254.G1Point sigma0; // 0x40
BN254.G1Point sigma1; // 0x60
BN254.G1Point sigma2; // 0x80
BN254.G1Point sigma3; // 0xA0
BN254.G1Point sigma4; // 0xC0
// commitment to selector poly
// first 4 are linear combination selector
BN254.G1Point q1; // 0xE0
BN254.G1Point q2; // 0x100
BN254.G1Point q3; // 0x120
BN254.G1Point q4; // 0x140
// multiplication selector for 1st, 2nd wire
BN254.G1Point qM12; // 0x160
// multiplication selector for 3rd, 4th wire
BN254.G1Point qM34; // 0x180
// output selector
BN254.G1Point qO; // 0x1A0
// constant term selector
BN254.G1Point qC; // 0x1C0
// rescue selector qH1 * w_ai^5
BN254.G1Point qH1; // 0x1E0
// rescue selector qH2 * w_bi^5
BN254.G1Point qH2; // 0x200
// rescue selector qH3 * w_ci^5
BN254.G1Point qH3; // 0x220
// rescue selector qH4 * w_di^5
BN254.G1Point qH4; // 0x240
// elliptic curve selector
BN254.G1Point qEcc; // 0x260
// serialized G2 point in SRS (compressed, little-endian, 64 bytes)
// we store the 64 bytes as 2 * bytes32 (first 32 bytes as `g2LSB`)
// (G1 points in SRS are implicitly committed via poly commitments)
bytes32 g2LSB; // 0x280
bytes32 g2MSB; // 0x2A0
}
IRewardClaim
This interface contains the methods, events and errors for claiming Espresso staking rewards.
This interface does not include administrative functionality of the RewardClaim contract.
Functions
claimRewards
Claim staking rewards
Obtain authData from the Espresso query service API.
function claimRewards(uint256 lifetimeRewards, bytes calldata authData) external;
Parameters
| Name | Type | Description |
|---|---|---|
lifetimeRewards | uint256 | Total earned lifetime rewards for the user @param |
authData | bytes | inputs required for authentication of lifetime rewards amount. |
claimedRewards
Check amount of rewards claimed by a user
function claimedRewards(address claimer) external view returns (uint256);
totalClaimed
Total amount claimed by all users
function totalClaimed() external view returns (uint256);
Events
RewardsClaimed
User claimed rewards
event RewardsClaimed(address indexed user, uint256 amount);
Errors
InvalidAuthRoot
Unable to authenticate rewards against Light Client contract
error InvalidAuthRoot();
AlreadyClaimed
All available rewards already claimed
error AlreadyClaimed();
InvalidRewardAmount
Reward amount must be greater than zero
error InvalidRewardAmount();
DailyLimitExceeded
A claim would exceed the remaining daily capacity
error DailyLimitExceeded();
Contents
Transcript
Functions
appendMessage
function appendMessage(TranscriptData memory self, bytes memory message) internal pure;
appendChallenge
function appendChallenge(TranscriptData memory self, uint256 challenge) internal pure;
appendCommitments
function appendCommitments(TranscriptData memory self, BN254.G1Point[] memory comms)
internal
pure;
appendCommitment
function appendCommitment(TranscriptData memory self, BN254.G1Point memory comm) internal pure;
getChallenge
function getChallenge(TranscriptData memory self) internal pure returns (uint256 ret);
appendVkAndPubInput
Append the verifying key and the public inputs to the transcript.
function appendVkAndPubInput(
TranscriptData memory self,
IPlonkVerifier.VerifyingKey memory verifyingKey,
uint256[] memory publicInput
) internal pure;
Parameters
| Name | Type | Description |
|---|---|---|
self | TranscriptData | |
verifyingKey | IPlonkVerifier.VerifyingKey | verifying key |
publicInput | uint256[] | a list of field elements |
appendProofEvaluations
Append the proof to the transcript. Only used for test purposes.
function appendProofEvaluations(
TranscriptData memory self,
IPlonkVerifier.PlonkProof memory proof
) internal pure;
Structs
TranscriptData
struct TranscriptData {
bytes32 state;
bytes transcript;
}
Contents
- BLSSig
- ERC1967Proxy
- EdOnBN254
- LightClientStateUpdateVK
- LightClientStateUpdateVKV2
- LightClientStateUpdateVKV3
- PlonkVerifier
- PlonkVerifierV2
- PlonkVerifierV3
- PolynomialEval
- PolynomialEvalV2
- PolynomialEvalV3
- RewardMerkleTreeVerifier
BLSSig
test top This library implements the verification of the BLS signature scheme over the BN254 curve following the rust implementation at https://github.com/EspressoSystems/jellyfish/blob/e1e683c287f20160738e6e737295dd8f9e70577a/primitives/src/signatures/bls_over_bn254.rs
Functions
_uint256FromBytesLittleEndian
function _uint256FromBytesLittleEndian(uint8[] memory input) private pure returns (uint256);
expand
Takes a sequence of bytes and turn in into another sequence of bytes with fixed size. Equivalent of https://github.com/arkworks-rs/algebra/blob/1f7b3c6b215e98fa3130b39d2967f6b43df41e04/ff/src/fields/field_hashers/expander/mod.rs#L37
function expand(bytes memory message) internal pure returns (bytes memory);
Parameters
| Name | Type | Description |
|---|---|---|
message | bytes | message to be “expanded” |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes | fixed size array of bytes |
hashToField
Hash a sequence of bytes to a field element in Fq. Equivalent of https://github.com/arkworks-rs/algebra/blob/1f7b3c6b215e98fa3130b39d2967f6b43df41e04/ff/src/fields/field_hashers/mod.rs#L65
function hashToField(bytes memory message) internal pure returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
message | bytes | input message to be hashed |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | field element in Fq |
hashToCurve
Hash a sequence of bytes to a group element in BN254.G_1. We use the hash-and-pray algorithm for now. Rust implementation can be found at https://github.com/EspressoSystems/jellyfish/blob/e1e683c287f20160738e6e737295dd8f9e70577a/primitives/src/signatures/bls_over_bn254.rs#L318
function hashToCurve(bytes memory input) internal view returns (BN254.G1Point memory);
Parameters
| Name | Type | Description |
|---|---|---|
input | bytes | message to be hashed |
Returns
| Name | Type | Description |
|---|---|---|
<none> | BN254.G1Point | group element in G_1 |
verifyBlsSig
Verify a bls signature. Reverts if the signature is invalid
function verifyBlsSig(bytes memory message, BN254.G1Point memory sig, BN254.G2Point memory pk)
internal
view;
Parameters
| Name | Type | Description |
|---|---|---|
message | bytes | message to check the signature against |
sig | BN254.G1Point | signature represented as a point in BN254.G_1 |
pk | BN254.G2Point | public key represented as a point in BN254.G_2 |
Errors
BLSSigVerificationFailed
error BLSSigVerificationFailed();
ERC1967Proxy
Inherits: Proxy
This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an implementation address that can be changed. This address is stored in storage in the location specified by https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn’t conflict with the storage layout of the implementation behind the proxy.
Functions
constructor
Initializes the upgradeable proxy with an initial implementation specified by
implementation.
If _data is nonempty, it’s used as data in a delegate call to implementation. This will
typically be an
encoded function call, and allows initializing the storage of the proxy like a Solidity
constructor.
Requirements:
- If
datais empty,msg.valuemust be zero.
constructor(address implementation, bytes memory _data) payable;
_implementation
Returns the current implementation address.
TIP: To get this value clients can read directly from the storage slot shown below (specified
by EIP1967) using
the https://eth.wiki/json-rpc/API#eth_getstorageat[eth_getStorageAt] RPC call.
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
function _implementation() internal view virtual override returns (address);
EdOnBN254
Edward curve on BN254. This library only implements a serialization function that is consistent with Arkworks’ format. It does not support any group operations.
State Variables
P_MOD
uint256 public constant P_MOD =
21888242871839275222246405745257275088548364400416034343698204186575808495617
Functions
isYNegative
Check if y-coordinate of G1 point is negative.
function isYNegative(EdOnBN254Point memory point) internal pure returns (bool);
isEqual
Check if two points are equal
function isEqual(EdOnBN254Point memory a, EdOnBN254Point memory b)
internal
pure
returns (bool);
Structs
EdOnBN254Point
struct EdOnBN254Point {
uint256 x;
uint256 y;
}
LightClientStateUpdateVK
Functions
getVk
function getVk() internal pure returns (IPlonkVerifier.VerifyingKey memory vk);
LightClientStateUpdateVKV2
Functions
getVk
function getVk() internal pure returns (IPlonkVerifier.VerifyingKey memory vk);
LightClientStateUpdateVKV3
Functions
getVk
function getVk() internal pure returns (IPlonkVerifier.VerifyingKey memory vk);
PlonkVerifier
The TurboPlonk formula is: qo * wo = pub_input + q_c + q_mul0 * w0 * w1 + q_mul1 * w2 * w3 + q_lc0 * w0 + q_lc1 * w1 + q_lc2 * w2 + q_lc3 * w3 + q_hash0 * w0 + q_hash1 * w1 + q_hash2 * w2 + q_hash3 * w3 + q_ecc * w0 * w1 * w2 * w3 * wo
State Variables
COSET_K1
uint256 internal constant COSET_K1 =
0x2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a
COSET_K2
uint256 internal constant COSET_K2 =
0x1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025
COSET_K3
uint256 internal constant COSET_K3 =
0x2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a
COSET_K4
uint256 internal constant COSET_K4 =
0x2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881
BETA_H_X0
uint256 internal constant BETA_H_X0 =
0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1
BETA_H_X1
uint256 internal constant BETA_H_X1 =
0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0
BETA_H_Y0
uint256 internal constant BETA_H_Y0 =
0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4
BETA_H_Y1
uint256 internal constant BETA_H_Y1 =
0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55
NUM_WIRE_TYPES
The number of wire types of the circuit, TurboPlonk has 5.
uint256 internal constant NUM_WIRE_TYPES = 5
Functions
verify
Verify a single TurboPlonk proofs.
function verify(
IPlonkVerifier.VerifyingKey memory verifyingKey,
uint256[7] memory publicInput,
IPlonkVerifier.PlonkProof memory proof
) external view returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
verifyingKey | IPlonkVerifier.VerifyingKey | The Plonk verification key |
publicInput | uint256[7] | The public input fields |
proof | IPlonkVerifier.PlonkProof | The TurboPlonk proof |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | _ A boolean indicating successful verification, false otherwise |
_validateProof
Validate all group points and scalar fields. Revert if any are invalid.
function _validateProof(IPlonkVerifier.PlonkProof memory proof) internal pure;
Parameters
| Name | Type | Description |
|---|---|---|
proof | IPlonkVerifier.PlonkProof | A Plonk proof |
_verify
function _verify(
IPlonkVerifier.VerifyingKey memory verifyingKey,
uint256[7] memory publicInput,
IPlonkVerifier.PlonkProof memory proof
) private view returns (bool);
_computeChallenges
function _computeChallenges(
IPlonkVerifier.VerifyingKey memory vk,
uint256[7] memory pi,
IPlonkVerifier.PlonkProof memory proof
) internal pure returns (Challenges memory res);
_computeLinPolyConstantTerm
Compute the constant term of the linearization polynomial.
r_plonk = PI - L1(x) * alpha^2 - alpha * \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) *
(w_m + gamma) * z(xw)
where m is the number of wire types.
function _computeLinPolyConstantTerm(
Challenges memory chal,
IPlonkVerifier.PlonkProof memory proof,
Poly.EvalData memory evalData
) internal pure returns (uint256 res);
_preparePolyCommitments
function _preparePolyCommitments(
IPlonkVerifier.VerifyingKey memory verifyingKey,
Challenges memory chal,
Poly.EvalData memory evalData,
IPlonkVerifier.PlonkProof memory proof
) internal view returns (BN254.G1Point memory e1, BN254.G1Point memory f1);
Returns
| Name | Type | Description |
|---|---|---|
e1 | BN254.G1Point | The [E]1 in Sec 8.4, step 11 of Plonk |
f1 | BN254.G1Point | The [F]1 in Sec 8.4, step 10 of Plonk |
_linearizationPolyComm
Compute the linearization poly commitment
function _linearizationPolyComm(
IPlonkVerifier.VerifyingKey memory verifyingKey,
Challenges memory challenge,
Poly.EvalData memory evalData,
IPlonkVerifier.PlonkProof memory proof
) private view returns (BN254.G1Point memory d1);
Parameters
| Name | Type | Description |
|---|---|---|
verifyingKey | IPlonkVerifier.VerifyingKey | The verifying key |
challenge | Challenges | A set of challenges |
evalData | Poly.EvalData | Polynomial evaluation data |
proof | IPlonkVerifier.PlonkProof | A Plonk proof |
Returns
| Name | Type | Description |
|---|---|---|
d1 | BN254.G1Point | The [D]1 in Step 9 of Plonk |
Errors
InvalidPlonkArgs
Plonk: invalid inputs, either mismatching lengths among input arguments or empty input.
error InvalidPlonkArgs();
WrongPlonkVK
Plonk: wrong verification key used.
error WrongPlonkVK();
Structs
Challenges
Plonk IOP verifier challenges.
struct Challenges {
uint256 alpha; // 0x00
uint256 alpha2; // 0x20
uint256 alpha3; // 0x40
uint256 beta; // 0x60
uint256 gamma; // 0x80
uint256 zeta; // 0xA0
uint256 v; // 0xC0
uint256 u; // 0xE0
}
PlonkVerifierV2
The TurboPlonk formula is: qo * wo = pub_input + q_c + q_mul0 * w0 * w1 + q_mul1 * w2 * w3 + q_lc0 * w0 + q_lc1 * w1 + q_lc2 * w2 + q_lc3 * w3 + q_hash0 * w0 + q_hash1 * w1 + q_hash2 * w2 + q_hash3 * w3 + q_ecc * w0 * w1 * w2 * w3 * wo
State Variables
COSET_K1
uint256 public constant COSET_K1 =
0x2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a
COSET_K2
uint256 public constant COSET_K2 =
0x1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025
COSET_K3
uint256 public constant COSET_K3 =
0x2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a
COSET_K4
uint256 public constant COSET_K4 =
0x2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881
BETA_H_X0
uint256 public constant BETA_H_X0 =
0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1
BETA_H_X1
uint256 public constant BETA_H_X1 =
0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0
BETA_H_Y0
uint256 public constant BETA_H_Y0 =
0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4
BETA_H_Y1
uint256 public constant BETA_H_Y1 =
0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55
NUM_WIRE_TYPES
The number of wire types of the circuit, TurboPlonk has 5.
uint256 internal constant NUM_WIRE_TYPES = 5
Functions
verify
Verify a single TurboPlonk proofs.
function verify(
IPlonkVerifier.VerifyingKey memory verifyingKey,
uint256[11] memory publicInput,
IPlonkVerifier.PlonkProof memory proof
) external view returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
verifyingKey | IPlonkVerifier.VerifyingKey | The Plonk verification key |
publicInput | uint256[11] | The public input fields |
proof | IPlonkVerifier.PlonkProof | The TurboPlonk proof |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | _ A boolean indicating successful verification, false otherwise |
_validateProof
Validate all group points and scalar fields. Revert if any are invalid.
function _validateProof(IPlonkVerifier.PlonkProof memory proof) internal pure;
Parameters
| Name | Type | Description |
|---|---|---|
proof | IPlonkVerifier.PlonkProof | A Plonk proof |
_verify
function _verify(
IPlonkVerifier.VerifyingKey memory verifyingKey,
uint256[11] memory publicInput,
IPlonkVerifier.PlonkProof memory proof
) private view returns (bool);
_computeChallenges
function _computeChallenges(
IPlonkVerifier.VerifyingKey memory vk,
uint256[11] memory pi,
IPlonkVerifier.PlonkProof memory proof
) internal pure returns (Challenges memory res);
_computeLinPolyConstantTerm
Compute the constant term of the linearization polynomial.
r_plonk = PI - L1(x) * alpha^2 - alpha * \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) *
(w_m + gamma) * z(xw)
where m is the number of wire types.
function _computeLinPolyConstantTerm(
Challenges memory chal,
IPlonkVerifier.PlonkProof memory proof,
Poly.EvalData memory evalData
) internal pure returns (uint256 res);
_preparePolyCommitments
function _preparePolyCommitments(
IPlonkVerifier.VerifyingKey memory verifyingKey,
Challenges memory chal,
Poly.EvalData memory evalData,
IPlonkVerifier.PlonkProof memory proof
) internal view returns (BN254.G1Point memory e1, BN254.G1Point memory f1);
Returns
| Name | Type | Description |
|---|---|---|
e1 | BN254.G1Point | The [E]1 in Sec 8.4, step 11 of Plonk |
f1 | BN254.G1Point | The [F]1 in Sec 8.4, step 10 of Plonk |
_linearizationPolyComm
Compute the linearization poly commitment
function _linearizationPolyComm(
IPlonkVerifier.VerifyingKey memory verifyingKey,
Challenges memory challenge,
Poly.EvalData memory evalData,
IPlonkVerifier.PlonkProof memory proof
) private view returns (BN254.G1Point memory d1);
Parameters
| Name | Type | Description |
|---|---|---|
verifyingKey | IPlonkVerifier.VerifyingKey | The verifying key |
challenge | Challenges | A set of challenges |
evalData | Poly.EvalData | Polynomial evaluation data |
proof | IPlonkVerifier.PlonkProof | A Plonk proof |
Returns
| Name | Type | Description |
|---|---|---|
d1 | BN254.G1Point | The [D]1 in Step 9 of Plonk |
Errors
InvalidPlonkArgs
Plonk: invalid inputs, either mismatching lengths among input arguments or empty input.
error InvalidPlonkArgs();
WrongPlonkVK
Plonk: wrong verification key used.
error WrongPlonkVK();
Structs
Challenges
Plonk IOP verifier challenges.
struct Challenges {
uint256 alpha; // 0x00
uint256 alpha2; // 0x20
uint256 alpha3; // 0x40
uint256 beta; // 0x60
uint256 gamma; // 0x80
uint256 zeta; // 0xA0
uint256 v; // 0xC0
uint256 u; // 0xE0
}
PlonkVerifierV3
The TurboPlonk formula is: qo * wo = pub_input + q_c + q_mul0 * w0 * w1 + q_mul1 * w2 * w3 + q_lc0 * w0 + q_lc1 * w1 + q_lc2 * w2 + q_lc3 * w3 + q_hash0 * w0 + q_hash1 * w1 + q_hash2 * w2 + q_hash3 * w3 + q_ecc * w0 * w1 * w2 * w3 * wo
State Variables
COSET_K1
uint256 public constant COSET_K1 =
0x2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a
COSET_K2
uint256 public constant COSET_K2 =
0x1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025
COSET_K3
uint256 public constant COSET_K3 =
0x2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a
COSET_K4
uint256 public constant COSET_K4 =
0x2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881
BETA_H_X0
uint256 public constant BETA_H_X0 =
0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1
BETA_H_X1
uint256 public constant BETA_H_X1 =
0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0
BETA_H_Y0
uint256 public constant BETA_H_Y0 =
0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4
BETA_H_Y1
uint256 public constant BETA_H_Y1 =
0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55
NUM_WIRE_TYPES
The number of wire types of the circuit, TurboPlonk has 5.
uint256 internal constant NUM_WIRE_TYPES = 5
Functions
verify
Verify a single TurboPlonk proofs.
function verify(
IPlonkVerifier.VerifyingKey memory verifyingKey,
uint256[5] memory publicInput,
IPlonkVerifier.PlonkProof memory proof
) external view returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
verifyingKey | IPlonkVerifier.VerifyingKey | The Plonk verification key |
publicInput | uint256[5] | The public input fields |
proof | IPlonkVerifier.PlonkProof | The TurboPlonk proof |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | _ A boolean indicating successful verification, false otherwise |
_validateProof
Validate all group points and scalar fields. Revert if any are invalid.
function _validateProof(IPlonkVerifier.PlonkProof memory proof) internal pure;
Parameters
| Name | Type | Description |
|---|---|---|
proof | IPlonkVerifier.PlonkProof | A Plonk proof |
_verify
function _verify(
IPlonkVerifier.VerifyingKey memory verifyingKey,
uint256[5] memory publicInput,
IPlonkVerifier.PlonkProof memory proof
) private view returns (bool);
_computeChallenges
function _computeChallenges(
IPlonkVerifier.VerifyingKey memory vk,
uint256[5] memory pi,
IPlonkVerifier.PlonkProof memory proof
) internal pure returns (Challenges memory res);
_computeLinPolyConstantTerm
Compute the constant term of the linearization polynomial.
r_plonk = PI - L1(x) * alpha^2 - alpha * \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) *
(w_m + gamma) * z(xw)
where m is the number of wire types.
function _computeLinPolyConstantTerm(
Challenges memory chal,
IPlonkVerifier.PlonkProof memory proof,
Poly.EvalData memory evalData
) internal pure returns (uint256 res);
_preparePolyCommitments
function _preparePolyCommitments(
IPlonkVerifier.VerifyingKey memory verifyingKey,
Challenges memory chal,
Poly.EvalData memory evalData,
IPlonkVerifier.PlonkProof memory proof
) internal view returns (BN254.G1Point memory e1, BN254.G1Point memory f1);
Returns
| Name | Type | Description |
|---|---|---|
e1 | BN254.G1Point | The [E]1 in Sec 8.4, step 11 of Plonk |
f1 | BN254.G1Point | The [F]1 in Sec 8.4, step 10 of Plonk |
_linearizationPolyComm
Compute the linearization poly commitment
function _linearizationPolyComm(
IPlonkVerifier.VerifyingKey memory verifyingKey,
Challenges memory challenge,
Poly.EvalData memory evalData,
IPlonkVerifier.PlonkProof memory proof
) private view returns (BN254.G1Point memory d1);
Parameters
| Name | Type | Description |
|---|---|---|
verifyingKey | IPlonkVerifier.VerifyingKey | The verifying key |
challenge | Challenges | A set of challenges |
evalData | Poly.EvalData | Polynomial evaluation data |
proof | IPlonkVerifier.PlonkProof | A Plonk proof |
Returns
| Name | Type | Description |
|---|---|---|
d1 | BN254.G1Point | The [D]1 in Step 9 of Plonk |
Errors
InvalidPlonkArgs
Plonk: invalid inputs, either mismatching lengths among input arguments or empty input.
error InvalidPlonkArgs();
WrongPlonkVK
Plonk: wrong verification key used.
error WrongPlonkVK();
Structs
Challenges
Plonk IOP verifier challenges.
struct Challenges {
uint256 alpha; // 0x00
uint256 alpha2; // 0x20
uint256 alpha3; // 0x40
uint256 beta; // 0x60
uint256 gamma; // 0x80
uint256 zeta; // 0xA0
uint256 v; // 0xC0
uint256 u; // 0xE0
}
PolynomialEval
Functions
newEvalDomain
Create a new Radix2EvalDomain with domainSize which should be power of 2.
Will revert if domainSize is not among {2^5, 2^16, 2^20}
The hardcoded values are generated by the rust script eval-domain.
function newEvalDomain(uint256 domainSize) internal pure returns (EvalDomain memory);
evaluateVanishingPoly
function evaluateVanishingPoly(EvalDomain memory self, uint256 zeta)
internal
pure
returns (uint256 res);
evaluateLagrangeOne
Evaluate the lagrange polynomial at point zeta given the vanishing polynomial
evaluation vanish_eval.
function evaluateLagrangeOne(
EvalDomain memory self,
BN254.ScalarField zeta,
BN254.ScalarField vanishEval
) internal view returns (BN254.ScalarField res);
evaluatePiPoly
Evaluate public input polynomial at point zeta.
function evaluatePiPoly(
EvalDomain memory self,
uint256[7] memory pi,
uint256 zeta,
uint256 vanishingPolyEval
) internal view returns (uint256 res);
evalDataGen
compute the EvalData for a given domain and a challenge zeta
function evalDataGen(EvalDomain memory self, uint256 zeta, uint256[7] memory publicInput)
internal
view
returns (EvalData memory evalData);
Errors
UnsupportedDegree
Unsupported polynomial degree, currently size must in 2^{14~17}.
error UnsupportedDegree();
Structs
EvalDomain
a Radix 2 Evaluation Domain
struct EvalDomain {
uint256 logSize; // log_2(self.size)
uint256 sizeInv; // Inverse of the size in the field
uint256[7] elements; // 1, g, g^2, ..., g^6
}
EvalData
stores vanishing poly, lagrange at 1, and Public input poly
struct EvalData {
BN254.ScalarField vanishEval;
BN254.ScalarField lagrangeOne;
BN254.ScalarField piEval;
}
PolynomialEvalV2
Functions
newEvalDomain
Create a new Radix2EvalDomain with domainSize which should be power of 2.
Will revert if domainSize is not among {2^5, 2^16, 2^20}
The hardcoded values are generated by the rust script eval-domain.
function newEvalDomain(uint256 domainSize) internal pure returns (EvalDomain memory);
evaluateVanishingPoly
function evaluateVanishingPoly(EvalDomain memory domain, uint256 zeta)
internal
pure
returns (uint256 res);
evaluateLagrangeOne
Evaluate the lagrange polynomial at point zeta given the vanishing polynomial
evaluation vanish_eval.
function evaluateLagrangeOne(
EvalDomain memory domain,
BN254.ScalarField zeta,
BN254.ScalarField vanishEval
) internal view returns (BN254.ScalarField res);
evaluatePiPoly
Evaluate public input polynomial at point zeta.
function evaluatePiPoly(
EvalDomain memory domain,
uint256[11] memory pi,
uint256 zeta,
uint256 vanishingPolyEval
) internal view returns (uint256 res);
evalDataGen
compute the EvalData for a given domain and a challenge zeta
function evalDataGen(EvalDomain memory domain, uint256 zeta, uint256[11] memory publicInput)
internal
view
returns (EvalData memory evalData);
Errors
UnsupportedDegree
Unsupported polynomial degree, currently size must in 2^{14~17}.
error UnsupportedDegree();
Structs
EvalDomain
a Radix 2 Evaluation Domain
struct EvalDomain {
uint256 logSize; // log_2(domain.size)
uint256 sizeInv; // Inverse of the size in the field
uint256[11] elements; // 1, g, g^2, ..., g^10
}
EvalData
stores vanishing poly, lagrange at 1, and Public input poly
struct EvalData {
BN254.ScalarField vanishEval;
BN254.ScalarField lagrangeOne;
BN254.ScalarField piEval;
}
PolynomialEvalV3
Functions
newEvalDomain
Create a new Radix2EvalDomain with domainSize which should be power of 2.
Will revert if domainSize is not among {2^5, 2^16, 2^20}
The hardcoded values are generated by the rust script eval-domain.
function newEvalDomain(uint256 domainSize) internal pure returns (EvalDomain memory);
evaluateVanishingPoly
function evaluateVanishingPoly(EvalDomain memory domain, uint256 zeta)
internal
pure
returns (uint256 res);
evaluateLagrangeOne
Evaluate the lagrange polynomial at point zeta given the vanishing polynomial
evaluation vanish_eval.
function evaluateLagrangeOne(
EvalDomain memory domain,
BN254.ScalarField zeta,
BN254.ScalarField vanishEval
) internal view returns (BN254.ScalarField res);
evaluatePiPoly
Evaluate public input polynomial at point zeta.
function evaluatePiPoly(
EvalDomain memory domain,
uint256[5] memory pi,
uint256 zeta,
uint256 vanishingPolyEval
) internal view returns (uint256 res);
evalDataGen
compute the EvalData for a given domain and a challenge zeta
function evalDataGen(EvalDomain memory domain, uint256 zeta, uint256[5] memory publicInput)
internal
view
returns (EvalData memory evalData);
Errors
UnsupportedDegree
Unsupported polynomial degree, currently size must in 2^{14~17}.
error UnsupportedDegree();
Structs
EvalDomain
a Radix 2 Evaluation Domain
struct EvalDomain {
uint256 logSize; // log_2(domain.size)
uint256 sizeInv; // Inverse of the size in the field
uint256[5] elements; // 1, g, g^2, g^3, g^4
}
EvalData
stores vanishing poly, lagrange at 1, and Public input poly
struct EvalData {
BN254.ScalarField vanishEval;
BN254.ScalarField lagrangeOne;
BN254.ScalarField piEval;
}
RewardMerkleTreeVerifier
Title: RewardMerkleTreeVerifier
Solidity verifier for RewardMerkleTreeV2 compatible with Espresso’s reward system
- Arity: 2 (binary tree)
- Depth: 160 levels
- Key length: 20 bytes (160 bits) - Ethereum addresses
- EVM native keccak hash
- Double hashing of leaves as cheap domain separator
State Variables
TREE_DEPTH
uint256 public constant TREE_DEPTH = 160
Functions
_hashLeaf
function _hashLeaf(uint256 value) internal pure returns (bytes32);
_hashInternal
function _hashInternal(bytes32 left, bytes32 right) internal pure returns (bytes32 hash);
computeRoot
Compute reward commitment from a key-value pair and proof.
Designed to authenticate non-zero values for non-zero keys; caller must ensure neither key nor value is zero.
function computeRoot(address key, uint256 value, bytes32[TREE_DEPTH] memory proof)
internal
pure
returns (bytes32);
Parameters
| Name | Type | Description |
|---|---|---|
key | address | The key to prove - Ethereum address |
value | uint256 | The value to prove - lifetime earned rewards amount |
proof | bytes32[TREE_DEPTH] | The membership proof containing sibling hashes and numLeaves |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes32 | The computed reward commitment |
EspToken
Inherits: Initializable, ERC20Upgradeable, OwnableUpgradeable, UUPSUpgradeable
Title: EspToken
ERC20 token for the Espresso network, upgradeable via UUPS.
Upgradeability & storage layout (frozen-inheritance pattern)
We intentionally do not use __gap slots. Once a version is deployed,
its storage layout is frozen and never modified. New state variables are
added only in a new child contract (V2, V3, …) that inherits from the
previous version and appends fields at the end. This preserves slot order
across upgrades without relying on gaps. (Note: upstream OZ parents may
include their own gaps—those remain untouched.)
Functions
constructor
since the constructor initializes storage on this contract we disable it
storage is on the proxy contract since it calls this contract via delegatecall
Note: oz-upgrades-unsafe-allow: constructor
constructor() ;
initialize
This contract is called by the proxy when you deploy this contract
function initialize(
address owner,
address initialRecipient,
uint256 initialSupply,
string memory name,
string memory symbol
) public initializer;
_authorizeUpgrade
only the owner can authorize an upgrade
function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner;
renounceOwnership
Cannot renounce ownership
Override renounceOwnership() to revert, preventing accidental or malicious ownership renunciation
function renounceOwnership() public virtual override onlyOwner;
getVersion
Use this to get the implementation contract version
function getVersion()
public
pure
virtual
returns (uint8 majorVersion, uint8 minorVersion, uint8 patchVersion);
Errors
OwnershipCannotBeRenounced
Cannot renounce ownership
error OwnershipCannotBeRenounced();
EspTokenV2
Inherits: EspToken
Title: EspTokenV2
Upgrades EspToken to allow minting by the RewardClaim contract
Upgradeability & storage layout (frozen-inheritance pattern)
We intentionally do not use __gap slots. Once a version is deployed,
its storage layout is frozen and never modified. New state variables are
added only in a new child contract (V2, V3, …) that inherits from the
previous version and appends fields at the end. This preserves slot order
across upgrades without relying on gaps. (Note: upstream OZ parents may
include their own gaps—those remain untouched.)
State Variables
rewardClaim
Address of the RewardClaim contract authorized to mint tokens
Can only be set once, during initialization.
address public rewardClaim
Functions
constructor
constructor() ;
initializeV2
Initializes the V2 upgrade with the RewardClaim contract address
function initializeV2(address _rewardClaim) public onlyOwner reinitializer(2);
Parameters
| Name | Type | Description |
|---|---|---|
_rewardClaim | address | Address of the RewardClaim contract |
mint
Mints new tokens to a specified address
Only the RewardClaim contract can mint new tokens
function mint(address to, uint256 amount) public;
Parameters
| Name | Type | Description |
|---|---|---|
to | address | Address to receive the minted tokens |
amount | uint256 | Number of tokens to mint |
getVersion
Returns the contract version
function getVersion()
public
pure
virtual
override
returns (uint8 majorVersion, uint8 minorVersion, uint8 patchVersion);
Returns
| Name | Type | Description |
|---|---|---|
majorVersion | uint8 | Major version number |
minorVersion | uint8 | Minor version number |
patchVersion | uint8 | Patch version number |
Errors
OnlyRewardClaim
A non-RewardClaim address attempts to mint
error OnlyRewardClaim();
ZeroRewardClaimAddress
RewardClaim address cannot be zero
error ZeroRewardClaimAddress();
FeeContract
Inherits: Initializable, OwnableUpgradeable, UUPSUpgradeable
State Variables
maxDepositAmount
max amount allowed to be deposited to prevent fat finger errors
uint256 public maxDepositAmount
minDepositAmount
uint256 public minDepositAmount
balances
store user balances in a mapping
mapping(address user => uint256 amount) public balances
Functions
constructor
since the constructor initializes storage on this contract we disable it
storage is on the proxy contract since it calls this contract via delegatecall
Note: oz-upgrades-unsafe-allow: constructor
constructor() ;
initialize
This contract is called by the proxy when you deploy this contract
function initialize(address multisig) public initializer;
fallback
Revert if a method name does not exist
fallback() external payable;
receive
Revert if no method name was called
receive() external payable;
deposit
Allows anyone to deposit an ETH balance for any user
the deposit amount is less than a specified threshold to prevent fat finger errors
function deposit(address user) public payable;
_authorizeUpgrade
only the owner can authorize an upgrade
function _authorizeUpgrade(address newImplementation) internal override onlyOwner;
renounceOwnership
Cannot renounce ownership
Override renounceOwnership() to revert, preventing accidental or malicious ownership renunciation
function renounceOwnership() public virtual override onlyOwner;
getVersion
Use this to get the implementation contract version
function getVersion()
public
pure
returns (uint8 majorVersion, uint8 minorVersion, uint8 patchVersion);
Events
Deposit
Notify a new deposit
event Deposit(address indexed user, uint256 amount);
Log
event Log(string func, uint256 gas);
Upgrade
upgrade event when the proxy updates the implementation it’s pointing to
event Upgrade(address implementation);
Errors
InvalidUserAddress
error types
error InvalidUserAddress();
DepositTooLarge
error DepositTooLarge();
DepositTooSmall
error DepositTooSmall();
FunctionDoesNotExist
error FunctionDoesNotExist();
NoFunctionCalled
error NoFunctionCalled();
OwnershipCannotBeRenounced
error OwnershipCannotBeRenounced();
InitializedAt
Inherits: Initializable
State Variables
initializedAtBlock
uint256 public initializedAtBlock
Functions
constructor
constructor() ;
initializeAtBlock
function initializeAtBlock() internal initializer;
LightClient
Inherits: Initializable, OwnableUpgradeable, UUPSUpgradeable
Title: Light Client Contract
This contract serves as an always-on client
that verifies HotShot’s state (Espresso’s consensus state) which can be used by
Rollup contracts on L1 (Ethereum).
This state is submitted by any state-prover with evidence which is
a SNARK proof that proves consensus.
This contract also keeps track of the current epoch.
For this version, the epoch is not used.
The light client state primarily consists of:
- the merkle root of finalized block commitments,
- the fee ledger commitment and
- the active stake table commitment
You can use this contract to keep track of its finalized states in safe, authenticated ways.
State Variables
genesisStakeTableState
genesis stake commitment
StakeTableState public genesisStakeTableState
genesisState
genesis block commitment
LightClientState public genesisState
finalizedState
Finalized HotShot’s light client state
LightClientState public finalizedState
permissionedProver
the address of the prover that can call the newFinalizedState function when the contract is in permissioned prover mode. This address is address(0) when the contract is not in permissioned prover mode
address public permissionedProver
stateHistoryRetentionPeriod
Max number of seconds worth of state commitments to record based on this block timestamp
uint32 public stateHistoryRetentionPeriod
stateHistoryFirstIndex
index of first block in block state series
use this instead of index 0 since old states would be set to zero to keep storage costs constant to stateHistoryRetentionPeriod
uint64 public stateHistoryFirstIndex
stateHistoryCommitments
an array to store the L1 block heights, HotShot Block Heights and their respective state history commitments
StateHistoryCommitment[] public stateHistoryCommitments
Functions
constructor
Constructor disables initializers to prevent the implementation contract from being initialized
This is standard practice for OpenZeppelin upgradeable contracts. Storage is on the proxy contract since it calls this cnotract via delegatecall
Note: oz-upgrades-unsafe-allow: constructor
constructor() ;
initialize
This contract is called by the proxy when you deploy this contract
function initialize(
LightClientState memory _genesis,
StakeTableState memory _genesisStakeTableState,
uint32 _stateHistoryRetentionPeriod,
address owner
) public initializer;
Parameters
| Name | Type | Description |
|---|---|---|
_genesis | LightClientState | The initial state of the light client |
_genesisStakeTableState | StakeTableState | |
_stateHistoryRetentionPeriod | uint32 | The maximum retention period (in seconds) for the state history. the min retention period allowed is 1 hour and max 365 days |
owner | address | The address of the contract owner |
currentBlockNumber
returns the current block number
function currentBlockNumber() public view virtual returns (uint256);
getVersion
Use this to get the implementation contract version
function getVersion()
public
pure
virtual
returns (uint8 majorVersion, uint8 minorVersion, uint8 patchVersion);
Returns
| Name | Type | Description |
|---|---|---|
majorVersion | uint8 | The major version of the contract |
minorVersion | uint8 | The minor version of the contract |
patchVersion | uint8 | The patch version of the contract |
_authorizeUpgrade
only the owner can authorize an upgrade
function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner;
renounceOwnership
Cannot renounce ownership
Override renounceOwnership() to revert, preventing accidental or malicious ownership renunciation
function renounceOwnership() public virtual override onlyOwner;
_initializeState
Initialization of contract variables happens in this method because the LightClient contract is upgradable and thus has its constructor method disabled.
function _initializeState(
LightClientState memory _genesis,
StakeTableState memory _genesisStakeTableState,
uint32 _stateHistoryRetentionPeriod
) internal;
Parameters
| Name | Type | Description |
|---|---|---|
_genesis | LightClientState | The initial state of the light client |
_genesisStakeTableState | StakeTableState | The initial stake table state of the light client |
_stateHistoryRetentionPeriod | uint32 | The maximum retention period (in seconds) for the state history. The min retention period allowed is 1 hour and the max is 365 days. |
newFinalizedState
Update the latest finalized light client state. It must be updated periodically, especially an update for the last block for every period has to be submitted before any newer state can be accepted since the stake table commitments of that block become the snapshots used for vote verifications later on.
While newState.stakeTable* refers to the (possibly) new stake table states,
the entire newState needs to be signed by stakers in finalizedState
if the permissionedProver is set, only the permissionedProver can call this function
the state history for stateHistoryRetentionPeriod L1 blocks are also recorded in the
stateHistoryCommitments array
function newFinalizedState(
LightClientState memory newState,
IPlonkVerifier.PlonkProof memory proof
) external virtual;
Parameters
| Name | Type | Description |
|---|---|---|
newState | LightClientState | new light client state |
proof | IPlonkVerifier.PlonkProof | PlonkProof |
_getVk
a technically unnecessary but luckily zero-cost indirection for the benefit of
having
IPlonkVerifier.VerifyingKey rust alloy bindings, included only if appear in a public func.
function _getVk() public pure virtual returns (IPlonkVerifier.VerifyingKey memory vk);
verifyProof
Verify the Plonk proof, marked as virtual for easier testing as we can swap VK
used in inherited contracts.
function verifyProof(LightClientState memory state, IPlonkVerifier.PlonkProof memory proof)
internal
virtual;
setPermissionedProver
set the permissionedProver to the non-zero address provided
this function can also be used to update the permissioned prover once it’s a different address to the current permissioned prover
function setPermissionedProver(address prover) public virtual onlyOwner;
disablePermissionedProverMode
set the permissionedProver to address(0)
if it was already disabled, then revert with the error, NoChangeRequired
function disablePermissionedProverMode() public virtual onlyOwner;
updateStateHistory
Updates the stateHistoryCommitments array when a new finalized state is added
and prunes the most outdated element starting from the first element if they fall outside
the
stateHistoryRetentionPeriod.
the block timestamp is used to determine if the stateHistoryCommitments array should be pruned, based on the stateHistoryRetentionPeriod (seconds).
A FIFO approach is used to remove the most outdated element from the start of the array. However, only one outdated element is removed per invocation of this function, even if multiple elements exceed the retention period. As a result, some outdated elements may remain in the array temporarily until subsequent invocations of this function.
the delete method does not reduce the array length but resets the value at the
specified index to zero. the stateHistoryFirstIndex variable acts as an offset to indicate
the starting point for reading the array, since the length of the array is not reduced
even after deletion.
function updateStateHistory(
uint64 blockNumber,
uint64 blockTimestamp,
LightClientState memory state
) internal;
Parameters
| Name | Type | Description |
|---|---|---|
blockNumber | uint64 | The block number of the new finalized state. |
blockTimestamp | uint64 | The block timestamp used to check the retention period. |
state | LightClientState | The new LightClientState being added to the array. |
lagOverEscapeHatchThreshold
checks if the state updates lag behind the specified block threshold based on the provided block number.
Reverts if there isn’t enough state history to make an accurate comparison. Reverts if the blockThreshold is zero
function lagOverEscapeHatchThreshold(uint256 blockNumber, uint256 blockThreshold)
public
view
virtual
returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
blockNumber | uint256 | The block number to compare against the latest state updates. |
blockThreshold | uint256 | The number of blocks updates this contract is allowed to lag behind. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | bool returns true if the lag exceeds the blockThreshold; otherwise, false. |
getHotShotCommitment
get the HotShot commitment that represents the Merkle root containing the leaf at the provided hotShotBlockHeight where the block height in the array is greater than
if the provided hotShotBlockHeight is greater than or equal to the latest commitment in the array, the function reverts.
function getHotShotCommitment(uint256 hotShotBlockHeight)
public
view
virtual
returns (BN254.ScalarField hotShotBlockCommRoot, uint64 hotshotBlockHeight);
Parameters
| Name | Type | Description |
|---|---|---|
hotShotBlockHeight | uint256 | the HotShot block height |
Returns
| Name | Type | Description |
|---|---|---|
hotShotBlockCommRoot | BN254.ScalarField | the HotShot commitment root |
hotshotBlockHeight | uint64 | the HotShot block height for the corresponding commitment root |
getStateHistoryCount
get the number of state history commitments
function getStateHistoryCount() public view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | uint256 The number of state history commitments |
setstateHistoryRetentionPeriod
sets the maximum retention period for storing block state history.
Reverts with InvalidMaxStateHistory if the provided value is less than 1 hour,
more than 365 days or less than or equal to the current state history retention period.
function setstateHistoryRetentionPeriod(uint32 historySeconds) public onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
historySeconds | uint32 | The maximum number of seconds for which state history updates will be stored, based on the block timestamp. It must be greater than or equal to the current state history retention period and must be at least 1 hour and max 365 days. |
isPermissionedProverEnabled
Check if permissioned prover is enabled
function isPermissionedProverEnabled() public view returns (bool);
Events
Upgrade
upgrade event when the proxy updates the implementation it’s pointing to
event Upgrade(address implementation);
PermissionedProverRequired
when a permissioned prover is set, this event is emitted.
event PermissionedProverRequired(address permissionedProver);
PermissionedProverNotRequired
when the permissioned prover is unset, this event is emitted.
event PermissionedProverNotRequired();
NewState
Event that a new finalized state has been successfully verified and updated
event NewState(
uint64 indexed viewNum, uint64 indexed blockHeight, BN254.ScalarField blockCommRoot
);
Errors
OutdatedState
The state is outdated and older than currently known finalizedState
error OutdatedState();
InvalidArgs
Invalid user inputs: wrong format or non-sensible arguments
error InvalidArgs();
InvalidProof
Wrong plonk proof or public inputs.
error InvalidProof();
WrongStakeTableUsed
Wrong stake table used, should match finalizedState
error WrongStakeTableUsed();
InvalidAddress
Invalid address
error InvalidAddress();
ProverNotPermissioned
Only a permissioned prover can perform this action
error ProverNotPermissioned();
NoChangeRequired
If the same mode or prover is sent to the function, then no change is required
error NoChangeRequired();
InsufficientSnapshotHistory
Invalid L1 Block for checking Light Client Updates, premature or in the future
error InsufficientSnapshotHistory();
InvalidHotShotBlockForCommitmentCheck
Invalid HotShot Block for checking HotShot commitments, premature or in the future
error InvalidHotShotBlockForCommitmentCheck();
InvalidMaxStateHistory
Invalid Max Block States
error InvalidMaxStateHistory();
OwnershipCannotBeRenounced
Cannot renounce ownership
error OwnershipCannotBeRenounced();
Structs
LightClientState
The finalized HotShot state (as the digest of the entire HotShot state)
struct LightClientState {
uint64 viewNum;
uint64 blockHeight;
BN254.ScalarField blockCommRoot;
}
Properties
| Name | Type | Description |
|---|---|---|
viewNum | uint64 | The latest view number of the finalized HotShot chain |
blockHeight | uint64 | The block height of the latest finalized block |
blockCommRoot | BN254.ScalarField | The merkle root of historical block commitments (BN254::ScalarField) |
StakeTableState
The finalized HotShot Stake state (as the digest of the entire HotShot state)
struct StakeTableState {
uint256 threshold;
BN254.ScalarField blsKeyComm;
BN254.ScalarField schnorrKeyComm;
BN254.ScalarField amountComm;
}
Properties
| Name | Type | Description |
|---|---|---|
threshold | uint256 | The (stake-weighted) quorum threshold for a QC to be considered as valid |
blsKeyComm | BN254.ScalarField | The commitment to the BlsVerKey column of the stake table |
schnorrKeyComm | BN254.ScalarField | The commitment to the SchnorrVerKey column of the table |
amountComm | BN254.ScalarField | The commitment to the stake amount column of the stake table |
StateHistoryCommitment
Simplified HotShot commitment struct
struct StateHistoryCommitment {
uint64 l1BlockHeight;
uint64 l1BlockTimestamp;
uint64 hotShotBlockHeight;
BN254.ScalarField hotShotBlockCommRoot;
}
Properties
| Name | Type | Description |
|---|---|---|
l1BlockHeight | uint64 | the block height of l1 when this state update was stored |
l1BlockTimestamp | uint64 | the block timestamp of l1 when this state update was stored |
hotShotBlockHeight | uint64 | The block height of the latest finalized HotShot block |
hotShotBlockCommRoot | BN254.ScalarField | The merkle root of historical block commitments (BN254::ScalarField) |
ArbSys
Functions
arbBlockNumber
function arbBlockNumber() external view returns (uint256);
LightClientArbitrum
Inherits: LightClient
Functions
currentBlockNumber
function currentBlockNumber() public view virtual override returns (uint256);
ArbSys
Functions
arbBlockNumber
function arbBlockNumber() external view returns (uint256);
LightClientArbitrumV2
Inherits: LightClientV2
Functions
currentBlockNumber
function currentBlockNumber() public view virtual override returns (uint256);
ArbSys
Functions
arbBlockNumber
function arbBlockNumber() external view returns (uint256);
LightClientArbitrumV3
Inherits: LightClientV3
Functions
currentBlockNumber
function currentBlockNumber() public view virtual override returns (uint256);
LightClientV2
Inherits: LightClient
LightClient V2: with stake table snapshot update during epoch change.
State Variables
blocksPerEpoch
number of blocks per epoch
uint64 public blocksPerEpoch
epochStartBlock
the block height when Epoch-related logic gets activated
uint64 public epochStartBlock
firstEpoch
the first epoch where dynamic stake table is activated, not the numerical value epoch=1
uint64 private firstEpoch
votingStakeTableState
stake table commitments for the current voting stakers
StakeTableState public votingStakeTableState
Functions
initializeV2
Initialize V2
function initializeV2(uint64 _blocksPerEpoch, uint64 _epochStartBlock)
public
onlyOwner
reinitializer(2);
getVersion
function getVersion()
public
pure
virtual
override
returns (uint8 majorVersion, uint8 minorVersion, uint8 patchVersion);
newFinalizedState
override the V1’s to disable calling it
function newFinalizedState(LightClientState memory, IPlonkVerifier.PlonkProof memory)
external
pure
override;
setStateHistoryRetentionPeriod
identical as LightClientV1’s setstateHistoryRetentionPeriod()
but this function name has the correct camelCase
function setStateHistoryRetentionPeriod(uint32 historySeconds) public virtual onlyOwner;
updateEpochStartBlock
function updateEpochStartBlock(uint64 newEpochStartBlock) public virtual onlyOwner;
newFinalizedState
See detailed doc in LightClient.sol
function newFinalizedState(
LightClientState memory newState,
StakeTableState memory nextStakeTable,
IPlonkVerifier.PlonkProof memory proof
) external virtual;
Parameters
| Name | Type | Description |
|---|---|---|
newState | LightClientState | |
nextStakeTable | StakeTableState | the stake table to use in the next block (same as the current except |
proof | IPlonkVerifier.PlonkProof |
_getVk
function _getVk() public pure virtual override returns (IPlonkVerifier.VerifyingKey memory vk);
verifyProof
compare to V1, we extend public input length from 7 to 11, use a newly generated VK, and enforce correct usage of the nextStakeTable outside the epoch change period.
function verifyProof(
LightClientState memory state,
StakeTableState memory nextStakeTable,
IPlonkVerifier.PlonkProof memory proof
) internal virtual;
currentEpoch
Returns the current epoch according the latest update on finalizedState
function currentEpoch() public view virtual returns (uint64);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint64 | current epoch (computed from the last known hotshot block number) |
epochFromBlockNumber
Calculate the epoch number from the hotshot block number
same logic as hotshot_types::utils::epoch_from_block_number()
function epochFromBlockNumber(uint64 _blockNum, uint64 _blocksPerEpoch)
public
pure
virtual
returns (uint64);
isEpochRoot
Decide if a block height is the an “epoch root” (defined as last block in epoch - 5)
function isEpochRoot(uint64 blockHeight) public view virtual returns (bool);
isGtEpochRoot
Returns true if the given block number is greater than the epoch root block
function isGtEpochRoot(uint64 blockHeight) public view virtual returns (bool);
Events
NewEpoch
When entering a new epoch and a new stake table snapshot.
event NewEpoch(uint64 epoch);
Errors
MissingEpochRootUpdate
The finalized state for the epoch root of every epoch should NOT be skipped
error MissingEpochRootUpdate();
DeprecatedApi
Invocation on outdated APIs on V1
error DeprecatedApi();
LightClientV3
Inherits: LightClientV2
Title: LightClientV3
LightClientV2 with an additional root for gas-efficient state authentication and
improved public input derivation for efficiency and future-proof.
State Variables
authRoot
a state value signed by validators as part of the extended light client state
uint256 public authRoot
_firstEpoch
Unfortunate re-declaration since V2 mark firstEpoch as private
uint64 internal _firstEpoch
Functions
initializeV3
function initializeV3() public onlyOwner reinitializer(3);
getVersion
function getVersion()
public
pure
virtual
override
returns (uint8 majorVersion, uint8 minorVersion, uint8 patchVersion);
newFinalizedState
override the V2’s to disable calling it
function newFinalizedState(
LightClientState memory,
StakeTableState memory,
IPlonkVerifier.PlonkProof memory
) external pure override;
newFinalizedState
See detailed doc in LightClient.sol and LightClientV2.sol
more detailed inline code comments, see LightClientV2.sol
diff w/ V2 is marked with “DIFF:” in comment
function newFinalizedState(
LightClientState memory newState,
StakeTableState memory nextStakeTable,
uint256 newAuthRoot,
IPlonkVerifier.PlonkProof memory proof
) external virtual;
Parameters
| Name | Type | Description |
|---|---|---|
newState | LightClientState | |
nextStakeTable | StakeTableState | |
newAuthRoot | uint256 | is the authentication root corresponding to newState |
proof | IPlonkVerifier.PlonkProof |
_getVk
function _getVk() public pure virtual override returns (IPlonkVerifier.VerifyingKey memory vk);
verifyProof
compare to V2, we change public input length from 11 to 5:
4 from votingStakeTableState, 1 from msg_signed := H(authenticated states)
function verifyProof(
LightClientState memory state,
StakeTableState memory nextStakeTable,
uint256 newAuthRoot,
IPlonkVerifier.PlonkProof memory proof
) internal virtual;
OpsTimelock
Inherits: TimelockController
Title: OpsTimelock
A timelock controller for contracts that require faster updates
Timelock used for operational control during early protocol phases. Grants privileged access to core team for upgrades or config changes with a short delay.
Functions
constructor
constructor(
uint256 minDelay,
address[] memory proposers,
address[] memory executors,
address admin
) TimelockController(minDelay, proposers, executors, admin);
RewardClaim
Inherits: IRewardClaim, Initializable, UUPSUpgradeable, PausableUpgradeable, AccessControlUpgradeable, ReentrancyGuardUpgradeable
Title: RewardClaim - Espresso Reward Claim Contract
Allows validators and delegators to claim ESP token rewards based on cryptographic proofs from the Espresso network.
Daily Limit Fairness: This contract enforces daily claim limits on a first-come, first-served basis. Once the limit is reached, remaining claimers must wait until the next day. In unlikely but not impossible scenarios they may be unable to claim for multiple days. The limit (default 1%, max 5% of supply) is set high enough that it should never be reached under normal operation. This is a simple defense-in-depth mechanism to limit potential damage in the unlikely case an attacker is able to circumvent authentication of reward claims. It is not a mechanism to throttle rate of withdrawals under normal operation. Stakers are encouraged to claim their rewards periodically and take advantage of staking their rewards.
Governance Architecture: This contract uses ONLY AccessControlUpgradeable.
- DEFAULT_ADMIN_ROLE: Can upgrade contract, manage roles, update daily limits
- PAUSER_ROLE: Can pause/unpause user facing methods in the contract during emergencies
Governance: This contract enforces a single-admin model.
currentAdminandDEFAULT_ADMIN_ROLEalways reference the same address and can only be changed viagrantRole(DEFAULT_ADMIN_ROLE, ...). Any attempt to revoke or renounce the default admin role reverts so that there is always a single admin.
State Variables
espToken
The ESP token contract
EspTokenV2 public espToken
lightClient
The light client contract
LightClientV3 public lightClient
claimedRewards
Tracks total lifetime rewards claimed by each address
mapping(address claimer => uint256 claimed) public claimedRewards
dailyLimitWei
Maximum amount (in Wei) that can be claimed per day across all claimers
Daily limits provide defense-in-depth security: in the unlikely event an exploit for the merkle proof verification is discovered, at most the daily limit can be minted before the contract is paused by the PAUSER_ROLE. This offers a second layer of protection beyond cryptographic verification.
This parameter is intentionally kept non-dynamic such that inflating the token
totalSupply will not inflate the value of this limiting parameter.
uint256 public dailyLimitWei
lastSetDailyLimitBasisPoints
Basis points used when daily limit was last set (for reference only)
This is a snapshot of the basis points parameter from the last setDailyLimit call. As total supply changes, this value becomes outdated and no longer represents the actual percentage that dailyLimitWei represents relative to current supply.
uint256 public lastSetDailyLimitBasisPoints
MAX_DAILY_LIMIT_BASIS_POINTS
Maximum daily limit as percentage of total supply in basis points (500 = 5%)
Hardcoded to prevent setting dangerously high limits without a contract upgrade. Increasing this value further would require upgrading the contract, which is intentional to ensure careful consideration and governance of security parameters.
uint256 public constant MAX_DAILY_LIMIT_BASIS_POINTS = 500
BPS_DENOMINATOR
Basis points denominator (100% = 10000 bps)
uint256 public constant BPS_DENOMINATOR = 10000
_currentDay
Current day number (days since epoch)
uint256 private _currentDay
_claimedToday
Amount claimed today across all claimers
No view functions provided for _currentDay or _claimedToday to avoid race conditions. Clients should use call/estimateGas on claimRewards() to check if a claim would succeed. Honest claims should never hit rate limits under normal operation.
It may be potentially useful to add a getter for when the daily limit will reset. We don’t expect to hit the daily limits, therefore implementation in the contract and in clients is not part of the initial release.
uint256 private _claimedToday
PAUSER_ROLE
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE")
currentAdmin
Current admin address with DEFAULT_ADMIN_ROLE
Tracks the single admin to enforce single-admin invariant
address public currentAdmin
totalClaimed
Total amount of rewards claimed across all users
Enables convenient monitoring of unclaimed rewards by subtracting totalClaimed
from total_reward_distributed in the Espresso block header. As long as the total unclaimed
rewards is less than the daily limit, honest claims are guaranteed to never exceed the daily
limit.
uint256 public totalClaimed
Functions
constructor
constructor() ;
initialize
Initializes the RewardClaim contract
Sets daily limit to 1% of total ESP token supply
function initialize(address _admin, address _espToken, address _lightClient, address _pauser)
external
virtual
initializer;
Parameters
| Name | Type | Description |
|---|---|---|
_admin | address | Address that will be granted DEFAULT_ADMIN_ROLE for contract administration |
_espToken | address | Address of the ESP token contract |
_lightClient | address | Address of the light client contract |
_pauser | address | Address to be granted the pauser role |
pause
function pause() external virtual onlyRole(PAUSER_ROLE);
unpause
function unpause() external virtual onlyRole(PAUSER_ROLE);
setDailyLimit
Updates the daily limit
This function computes an absolute daily limit in Wei by multiplying the supplied basis points with the current total supply of ESP tokens.
nonReentrant protects against reentrancy during the external call to totalSupply.
Unlikely to be exploited: we are calling our token, but the token is upgradable.
DO NOT REMOVE: Added for defense-in-depth.
function setDailyLimit(uint256 basisPoints)
external
virtual
onlyRole(DEFAULT_ADMIN_ROLE)
nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
basisPoints | uint256 | Daily limit as basis points of current total supply (1-500 for 0.01%-5%) |
claimRewards
Claim all unclaimed staking rewards
nonReentrant is not strictly necessary:
- claimedRewards updated before external call
- re-entrancy would change msg.sender making proof verification fail
- we are calling our token
The token is upgradable, the modifier makes re-entrancy simpler to reason about.
DO NOT REMOVE: added for defense-in-depth and clarity.
See RewardClaim.Reentrancy.Unit.t.sol for regression test.
function claimRewards(uint256 lifetimeRewards, bytes calldata authData)
external
virtual
whenNotPaused
nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
lifetimeRewards | uint256 | Total earned lifetime rewards for the user |
authData | bytes | Authentication data from Espresso query service |
getVersion
function getVersion()
external
pure
virtual
returns (uint8 majorVersion, uint8 minorVersion, uint8 patchVersion);
_enforceDailyLimit
See “Daily Limit Fairness” in contract docs.
function _enforceDailyLimit(uint256 amount) internal virtual;
_authorizeUpgrade
only the timelock can authorize an upgrade
function _authorizeUpgrade(address newImplementation)
internal
virtual
override
onlyRole(DEFAULT_ADMIN_ROLE);
grantRole
Override grantRole to enforce single-admin invariant for DEFAULT_ADMIN_ROLE
When granting DEFAULT_ADMIN_ROLE, automatically revokes it from the current admin. This ensures only one address has DEFAULT_ADMIN_ROLE at any time, atomically. This is intentionally not pausable for emergency governance access.
function grantRole(bytes32 role, address account) public virtual override;
renounceRole
Prevent renouncing DEFAULT_ADMIN_ROLE to preserve governance control
Override renounceRole() to revert when attempting to renounce DEFAULT_ADMIN_ROLE, preventing accidental or malicious admin role renunciation
Revokes role from the calling account.
Roles are often managed via {grantRole} and {revokeRole}: this function’s
purpose is to provide a mechanism for accounts to lose their privileges
if they are compromised (such as when a trusted device is misplaced).
If the calling account had been revoked role, emits a {RoleRevoked}
event.
Requirements:
- the caller must be
callerConfirmation. May emit a {RoleRevoked} event.
function renounceRole(bytes32 role, address callerConfirmation) public virtual override;
revokeRole
Prevent revoking DEFAULT_ADMIN_ROLE to preserve the single-admin invariant.
Revokes role from account.
If account had been granted role, emits a {RoleRevoked} event.
Requirements:
- the caller must have
role’s admin role. May emit a {RoleRevoked} event.
function revokeRole(bytes32 role, address account) public virtual override;
_verifyAuthRoot
function _verifyAuthRoot(uint256 lifetimeRewards, bytes calldata authData)
internal
view
virtual
returns (bool);
Events
DailyLimitUpdated
The daily limit is updated
event DailyLimitUpdated(uint256 oldLimit, uint256 newLimit);
Errors
ZeroDailyLimit
Attempting to set daily limit to zero
error ZeroDailyLimit();
DailyLimitTooHigh
Attempting to set daily limit above the maximum allowed percentage
error DailyLimitTooHigh();
NoChangeRequired
Attempting to set daily limit to the current value
error NoChangeRequired();
ZeroTotalSupply
Total ESP token supply is zero during initialization
error ZeroTotalSupply();
ZeroPauserAddress
Pauser address is zero during initialization
error ZeroPauserAddress();
ZeroAdminAddress
Admin address is zero during initialization
error ZeroAdminAddress();
ZeroLightClientAddress
Light client address is zero during initialization
error ZeroLightClientAddress();
ZeroTokenAddress
ESP token address is zero during initialization
error ZeroTokenAddress();
DefaultAdminCannotBeRenounced
Attempted to renounce DEFAULT_ADMIN_ROLE which would break governance
error DefaultAdminCannotBeRenounced();
DefaultAdminCannotBeRevoked
Attempted to revoke DEFAULT_ADMIN_ROLE which would break governance
error DefaultAdminCannotBeRevoked();
SafeExitTimelock
Inherits: TimelockController
Title: SafeExitTimelock
A timelock controller for contracts that can have a long delay before updates are applied
The delay on the contract is long enough for users to exit the system if they do not agree with the update
Functions
constructor
constructor(
uint256 minDelay,
address[] memory proposers,
address[] memory executors,
address admin
) TimelockController(minDelay, proposers, executors, admin);
StakeTable
Inherits: Initializable, InitializedAt, OwnableUpgradeable, UUPSUpgradeable
Title: Ethereum L1 component of the Espresso Global Confirmation Layer (GCL) stake table.
All functions are marked as virtual so that future upgrades can override them.
State Variables
lightClient
Reference to the light client contract.
Currently unused but will be used for slashing therefore already included in the contract.
ILightClient public lightClient
token
The staking token contract.
ERC20 public token
validators
All validators the contract knows about.
mapping(address account => Validator validator) public validators
blsKeys
BLS keys that have been seen by the contract
to simplify the reasoning about what keys and prevent some errors due to misconfigurations of validators the contract currently marks keys as used and only allow them to be used once. This for example prevents callers from accidentally registering the same BLS key twice.
mapping(bytes32 blsKeyHash => bool used) public blsKeys
validatorExits
Validators that have exited and the time at which delegators can claim their funds.
mapping(address validator => uint256 unlocksAt) public validatorExits
delegations
Currently active delegation amounts.
mapping(address validator => mapping(address delegator => uint256 amount)) public delegations
undelegations
Delegations held in escrow that are to be unlocked at a later time.
mapping(address validator => mapping(address delegator => Undelegation)) public undelegations
exitEscrowPeriod
The time (seconds) the contract will hold funds after undelegations are requested. Must allow ample time for node to exit active validator set and slashing evidence to be submitted.
uint256 public exitEscrowPeriod
Functions
constructor
since the constructor initializes storage on this contract we disable it
storage is on the proxy contract since it calls this contract via delegatecall
Note: oz-upgrades-unsafe-allow: constructor
constructor() ;
initialize
function initialize(
address _tokenAddress,
address _lightClientAddress,
uint256 _exitEscrowPeriod,
address _timelock
) public initializer;
initializeState
Initialize the state of the contract
function initializeState(
address _tokenAddress,
address _lightClientAddress,
uint256 _exitEscrowPeriod
) internal;
Parameters
| Name | Type | Description |
|---|---|---|
_tokenAddress | address | The address of the staking token |
_lightClientAddress | address | The address of the light client |
_exitEscrowPeriod | uint256 | The exit escrow period. Set to uint64.max to disable the exit escrow period. |
getVersion
Use this to get the implementation contract version
function getVersion()
public
pure
virtual
returns (uint8 majorVersion, uint8 minorVersion, uint8 patchVersion);
Returns
| Name | Type | Description |
|---|---|---|
majorVersion | uint8 | The major version of the contract |
minorVersion | uint8 | The minor version of the contract |
patchVersion | uint8 | The patch version of the contract |
_authorizeUpgrade
only the timelock can authorize an upgrade
function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner;
renounceOwnership
Prevent renouncing ownership to preserve governance control.
Override renounceOwnership() to revert, preventing accidental or malicious ownership renunciation
function renounceOwnership() public virtual override onlyOwner;
_hashBlsKey
Computes a hash value of some G2 point.
function _hashBlsKey(BN254.G2Point memory blsVK) public pure returns (bytes32);
Parameters
| Name | Type | Description |
|---|---|---|
blsVK | BN254.G2Point | BLS verification key in G2 |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes32 | keccak256(blsVK) |
ensureValidatorActive
function ensureValidatorActive(address validator) internal view;
ensureValidatorNotRegistered
function ensureValidatorNotRegistered(address validator) internal view;
ensureNewKey
function ensureNewKey(BN254.G2Point memory blsVK) internal view;
ensureNonZeroSchnorrKey
function ensureNonZeroSchnorrKey(EdOnBN254.EdOnBN254Point memory schnorrVK) internal pure;
registerValidator
Register a validator in the stake table
The function will revert if
- the validator is already registered
- the schnorr key is zero
- if the bls signature verification fails (this prevents rogue public-key attacks).
- the commission is > 100%
No validity check on schnorrVK due to gas cost of Rescue hash, UIs should perform
checks where possible and alert users.
function registerValidator(
BN254.G2Point memory blsVK,
EdOnBN254.EdOnBN254Point memory schnorrVK,
BN254.G1Point memory blsSig,
uint16 commission
) external virtual;
Parameters
| Name | Type | Description |
|---|---|---|
blsVK | BN254.G2Point | The BLS verification key |
schnorrVK | EdOnBN254.EdOnBN254Point | The Schnorr verification key (as the auxiliary info) |
blsSig | BN254.G1Point | The BLS signature that authenticates the ethereum account this function is called from |
commission | uint16 | in % with 2 decimals, from 0.00% (value 0) to 100% (value 10_000) |
deregisterValidator
Deregister a validator
function deregisterValidator() public virtual;
delegate
Delegate to a validator
function delegate(address validator, uint256 amount) public virtual;
Parameters
| Name | Type | Description |
|---|---|---|
validator | address | The validator to delegate to |
amount | uint256 | The amount to delegate |
undelegate
Undelegate from a validator
function undelegate(address validator, uint256 amount) public virtual;
Parameters
| Name | Type | Description |
|---|---|---|
validator | address | The validator to undelegate from |
amount | uint256 | The amount to undelegate |
claimWithdrawal
Withdraw previously delegated funds after an undelegation.
function claimWithdrawal(address validator) public virtual;
Parameters
| Name | Type | Description |
|---|---|---|
validator | address | The validator to withdraw from |
claimValidatorExit
Withdraw previously delegated funds after a validator has exited
function claimValidatorExit(address validator) public virtual;
Parameters
| Name | Type | Description |
|---|---|---|
validator | address | The validator to withdraw from |
updateConsensusKeys
Update the consensus keys for a validator
This function is used to update the consensus keys for a validator
This function can only be called by the validator itself when it hasn’t exited
The validator will need to give up either its old BLS key and/or old Schnorr key
The validator will need to provide a BLS signature to prove that the account owns the new BLS key
function updateConsensusKeys(
BN254.G2Point memory newBlsVK,
EdOnBN254.EdOnBN254Point memory newSchnorrVK,
BN254.G1Point memory newBlsSig
) external virtual;
Parameters
| Name | Type | Description |
|---|---|---|
newBlsVK | BN254.G2Point | The new BLS verification key |
newSchnorrVK | EdOnBN254.EdOnBN254Point | The new Schnorr verification key |
newBlsSig | BN254.G1Point | The BLS signature that the account owns the new BLS key |
Events
ValidatorRegistered
A registration of a new validator.
Signals to the confirmation layer that a new validator is ready to receive delegations in the stake table contract. The confirmation layer uses this event to keep track of the validator’s keys for the stake table.
The commission is in % with 2 decimals, from 0.00% (value 0) to 100% (value 10_000).
A validator registration is only valid if the BLS and Schnorr signature are valid. The GCL must verify this and otherwise discard the validator registration when it processes the event. The contract cannot verify the validity of the registration event and delegators will be able to deposit as soon as this event is emitted. In the event that a delegator delegates to an invalid validator the delegator can withdraw the delegation again in the same way they can withdraw other delegations.
UIs should do their best to prevent invalid, or duplicate registrations.
The verification key of the BLS keypair used for consensus signing is a
BN254.G2Point.
The verification key of the state signing schnorr keypair is an
EdOnBN254.EdOnBN254Point.
event ValidatorRegistered(
address indexed account,
BN254.G2Point blsVk,
EdOnBN254.EdOnBN254Point schnorrVk,
uint16 commission
);
ValidatorExit
A validator initiated an exit from stake table
All funds delegated to this validator are marked for withdrawal. Users can no longer
delegate to this validator. Their previously delegated funds are automatically undelegated.
After exitEscrowPeriod elapsed, delegators can claim the funds delegated to the exited
validator via claimValidatorExit.
The GCL removes this validator and all its delegations from the active validator set.
event ValidatorExit(address indexed validator);
Delegated
A Delegator delegated funds to a validator.
The tokens are transferred to the stake table contract.
The GCL adjusts the weight for this validator and the delegators delegation associated with it.
event Delegated(address indexed delegator, address indexed validator, uint256 amount);
Undelegated
A delegator undelegation funds from a validator.
The tokens are marked to be unlocked for withdrawal.
The GCL needs to update the stake table and adjust the weight for this validator and the delegators delegation associated with it.
event Undelegated(address indexed delegator, address indexed validator, uint256 amount);
ConsensusKeysUpdated
A validator updates their signing keys.
Similarly to registration events, the correctness cannot be fully determined by the contracts.
The confirmation layer needs to update the stake table with the new keys.
event ConsensusKeysUpdated(
address indexed account, BN254.G2Point blsVK, EdOnBN254.EdOnBN254Point schnorrVK
);
Withdrawal
A delegator claims unlocked funds.
This event is not relevant for the GCL. The events that remove stake from the stake
table are Undelegated and ValidatorExit.
event Withdrawal(address indexed account, uint256 amount);
Errors
ValidatorAlreadyRegistered
A user tries to register a validator with the same address
error ValidatorAlreadyRegistered();
ValidatorInactive
error ValidatorInactive();
ValidatorAlreadyExited
A validator has already exited.
error ValidatorAlreadyExited();
ValidatorNotExited
A validator has not exited yet.
error ValidatorNotExited();
PrematureWithdrawal
error PrematureWithdrawal();
InsufficientAllowance
error InsufficientAllowance(uint256, uint256);
InsufficientBalance
error InsufficientBalance(uint256);
NothingToWithdraw
error NothingToWithdraw();
InvalidSchnorrVK
error InvalidSchnorrVK();
BlsKeyAlreadyUsed
The BLS key has been previously registered in the contract.
error BlsKeyAlreadyUsed();
InvalidCommission
The commission value is invalid.
error InvalidCommission();
ZeroAddress
Contract dependencies initialized with zero address.
error ZeroAddress();
UndelegationAlreadyExists
An undelegation already exists for this validator and delegator.
error UndelegationAlreadyExists();
ZeroAmount
A zero amount would lead to a no-op.
error ZeroAmount();
OwnershipCannotBeRenounced
Attempted to renounce ownership which would break governance controls.
error OwnershipCannotBeRenounced();
ExitEscrowPeriodInvalid
The exit escrow period is invalid (either too short or too long)
error ExitEscrowPeriodInvalid();
Structs
Validator
Represents an Espresso validator and tracks funds currently delegated to them.
The delegatedAmount excludes funds that are currently marked for withdrawal via
undelegation or validator exit.
struct Validator {
uint256 delegatedAmount;
ValidatorStatus status;
}
Undelegation
Tracks an undelegation from a validator.
struct Undelegation {
uint256 amount;
uint256 unlocksAt;
}
Enums
ValidatorStatus
The status of a validator.
By default a validator is in the Unknown state. This means it has never registered. Upon
registration the status will become Active and if the validator deregisters its status
becomes Exited.
enum ValidatorStatus {
Unknown,
Active,
Exited
}
StakeTableV2
Inherits: StakeTable, PausableUpgradeable, AccessControlUpgradeable
Title: Ethereum L1 component of the Espresso Global Confirmation Layer (GCL) stake table.
This contract is an upgrade to the original StakeTable contract. On Espresso mainnet we will only use the V2 contract. On decaf the V2 is used to upgrade the V1 that was first deployed with the original proof of stake release.
The V2 contract contains the following changes:
- The functions to register validators and update consensus keys are updated to require both a
BLS signature and a Schnorr signature and emit the signatures via events so that the GCL can
verify them. The new functions and events have a V2 postfix. After the upgrade components that
support registration and key updates must use the V2 functions and listen to the V2 events. The
original functions revert with a
DeprecatedFunctionerror in V2. - The exit escrow period can be updated by the owner of the contract within valid bounds (15 blocks to 14 days).
- The following functions can be paused by the PAUSER_ROLE:
claimWithdrawal(...)claimValidatorExit(...)delegate(...)undelegate(...)deregisterValidator(...)registerValidatorV2(...)updateConsensusKeysV2(...)updateCommission(...)updateMetadataUri(...)When paused, these functions revert with a standard pausable error,EnforcedPause(). Only the PAUSER_ROLE can pause/unpause the contract. Note:updateExitEscrowPeriodis NOT pausable for emergency governance access.
- The
claimValidatorExitfunction is overridden to ensure that the validator’s delegatedAmount is updated during this method The update is deferred until the funds are actually withdrawn. - The
deregisterValidatorfunction is overridden to ensure that the validator’s delegatedAmount is not updated during this method as it was in v1. - The
updateExitEscrowPeriodfunction is added to allow governance to update the exit escrow period within valid bounds (15 blocks to 14 days). - The
pauseandunpausefunctions are added for emergency control. - The commission rate for validators can be updated with the
updateCommissionfunction. - The
activeStakevariable is added to allow governance to track the total stake in the contract. The activeStake is the total stake that is not awaiting exit or in exited state. - Unique undelegation IDs are assigned to each undelegation via an auto-incrementing counter
for better event tracking. The
undelegationIdspublic mapping stores IDs alongside the baseundelegationsmapping. EventsUndelegatedV2,WithdrawalClaimed, andValidatorExitClaimedinclude the undelegation ID as an indexed parameter for efficient querying and tracking. - Validators must provide a metadata URI during registration and can update it via
updateMetadataUri. The metadata URI is event-sourced only (not stored on-chain for gas efficiency). TheValidatorRegisteredV2event includes the metadata URI, and a newMetadataUriUpdatedevent is emitted when validators update their URI. Metadata URIs can be empty and cannot exceed 2048 bytes. - A minimum delegation amount (
minDelegateAmount) is enforced to prevent dust delegations and reduce state bloat. The minimum is initialized to 1 ESP token (1 ether) ininitializeV2and can be updated by governance via thesetMinDelegateAmountfunction. Thedelegatefunction reverts withDelegateAmountTooSmallif the delegation amount is below the minimum.
The StakeTableV2 contract ABI is a superset of the original ABI. Consumers of the
contract can use the V2 ABI, even if they would like to maintain backwards compatibility.
Governance: This contract enforces a single-admin model. owner() and
DEFAULT_ADMIN_ROLE always reference the same address and can only be
changed via transferOwnership() (directly or through
grantRole(DEFAULT_ADMIN_ROLE, ...), which delegates to the transfer). Any
attempt to revoke or renounce the default admin role, or to renounce
ownership, reverts. This removes governance drift.
All functions are marked as virtual so that future upgrades can override them.
State Variables
PAUSER_ROLE
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE")
MAX_METADATA_URI_LENGTH
Maximum length for metadata URIs (in bytes)
uint256 public constant MAX_METADATA_URI_LENGTH = 2048
MAX_COMMISSION_BPS
Maximum commission in basis points (100% = 10000 bps)
uint16 public constant MAX_COMMISSION_BPS = 10000
MIN_EXIT_ESCROW_PERIOD
Minimum exit escrow period (2 days)
This is a technical minimum bound enforced by the contract. Setting the exit escrow period to this minimum does not guarantee safety. The actual exit escrow period must be set such that the contract holds funds long enough until they are no longer staked in Espresso, allowing sufficient time for validators to exit the active validator set and for slashing evidence to be submitted. Governance should set a value appropriate for Espresso network parameters (e.g., blocksPerEpoch, blockTime, and epoch duration) to ensure security.
uint64 public constant MIN_EXIT_ESCROW_PERIOD = 2 days
MAX_EXIT_ESCROW_PERIOD
Maximum exit escrow period (14 days)
Reasonable upper bound to prevent excessive lockup periods
uint64 public constant MAX_EXIT_ESCROW_PERIOD = 14 days
minCommissionIncreaseInterval
Minimum time interval between commission increases (in seconds)
uint256 public minCommissionIncreaseInterval
maxCommissionIncrease
Maximum commission increase allowed per increase (in basis points)
uint16 public maxCommissionIncrease
activeStake
Total stake in active (not marked for exit) validators in the contract
uint256 public activeStake
minDelegateAmount
min delegate amount
uint256 public minDelegateAmount
commissionTracking
Commission tracking for each validator
mapping(address validator => CommissionTracking tracking) public commissionTracking
schnorrKeys
Schnorr keys that have been seen by the contract
ensures a bijective mapping between schnorr key and ethereum account and prevents some errors due to misconfigurations of validators the contract currently marks keys as used and only allow them to be used once. This for example prevents callers from accidentally registering the same Schnorr key twice.
mapping(bytes32 schnorrKey => bool used) public schnorrKeys
nextUndelegationId
Auto-incrementing counter for unique undelegation IDs
Initialized to 1 in initializeV2 so that 0 can be used to identify V1 undelegations
uint64 private nextUndelegationId
undelegationIds
Mapping from (validator, delegator) to undelegation ID
Separate from base Undelegation struct since base contract is immutable
mapping(address validator => mapping(address delegator => uint64 id)) private undelegationIds
Functions
constructor
Constructor
This function is overridden to disable initializers
constructor() ;
initializeV2
Reinitialize the contract
initialCommissions must be an empty array if the contract we’re upgrading has not been used before (e.g. on mainnet). On decaf (sepolia), this must be called with the current commissions of pre-existing validators read from L1 events.
Sets up roles and transfers ownership to admin. The deployer picks the admin address (timelock, multisig, etc.) based on config.
function initializeV2(
address pauser,
address admin,
uint256 initialActiveStake,
InitialCommission[] calldata initialCommissions
) public onlyOwner reinitializer(2);
Parameters
| Name | Type | Description |
|---|---|---|
pauser | address | The address to be granted the pauser role |
admin | address | The address to be granted the default admin role and ownership. This should be a timelock contract address, multisig, or another governance address. |
initialActiveStake | uint256 | The initial active stake in the contract |
initialCommissions | InitialCommission[] | commissions of validators |
getVersion
Get the version of the contract
This function is overridden to return the version of the contract
function getVersion()
public
pure
virtual
override
returns (uint8 majorVersion, uint8 minorVersion, uint8 patchVersion);
pause
Pause the contract
This function is only callable by the PAUSER_ROLE
function pause() external onlyRole(PAUSER_ROLE);
unpause
Unpause the contract
This function is only callable by the PAUSER_ROLE
function unpause() external onlyRole(PAUSER_ROLE);
transferOwnership
Transfers ownership and keeps DEFAULT_ADMIN_ROLE in sync Grants the role to new owner and revokes from old owner. Access control is enforced by both onlyRole(DEFAULT_ADMIN_ROLE) and super.transferOwnership() which requires onlyOwner. This ensures that only the current admin (who holds both ownership and DEFAULT_ADMIN_ROLE) can transfer ownership. This is intentionally not pausable for emergency governance access.
Transfers ownership of the contract to a new account (newOwner).
Can only be called by the current owner.
function transferOwnership(address newOwner)
public
virtual
override
onlyRole(DEFAULT_ADMIN_ROLE);
grantRole
Grants a role. Granting DEFAULT_ADMIN_ROLE transfers ownership first, which handles both role grant and ownership transfer atomically. This is intentionally not pausable for emergency governance access.
Grants role to account.
If account had not been already granted role, emits a {RoleGranted}
event.
Requirements:
- the caller must have
role’s admin role. May emit a {RoleGranted} event.
function grantRole(bytes32 role, address account) public virtual override;
revokeRole
Prevent revoking DEFAULT_ADMIN_ROLE to preserve the single-admin invariant.
Revokes role from account.
If account had been granted role, emits a {RoleRevoked} event.
Requirements:
- the caller must have
role’s admin role. May emit a {RoleRevoked} event.
function revokeRole(bytes32 role, address account) public virtual override;
renounceRole
Prevent renouncing DEFAULT_ADMIN_ROLE to preserve the single-admin invariant.
Revokes role from the calling account.
Roles are often managed via {grantRole} and {revokeRole}: this function’s
purpose is to provide a mechanism for accounts to lose their privileges
if they are compromised (such as when a trusted device is misplaced).
If the calling account had been revoked role, emits a {RoleRevoked}
event.
Requirements:
- the caller must be
callerConfirmation. May emit a {RoleRevoked} event.
function renounceRole(bytes32 role, address callerConfirmation) public virtual override;
claimValidatorExit
Withdraw previously delegated funds after a validator has exited
This function is overridden to deduct the amount from the validator’s delegatedAmount
and to add pausable functionality
since the delegated Amount is no longer updated during validator exit
function claimValidatorExit(address validator) public virtual override whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
validator | address | The validator to withdraw from |
claimWithdrawal
Withdraw previously delegated funds after an undelegation
This function is overridden to add pausable functionality and emit ID in event
function claimWithdrawal(address validator) public virtual override whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
validator | address | The validator to withdraw from |
delegate
Delegate funds to a validator
This function is overridden to add pausable functionality
The function body is copied from V1 to maintain checks-effects-interactions pattern.
function delegate(address validator, uint256 amount) public virtual override whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
validator | address | The validator to delegate to |
amount | uint256 | The amount to delegate |
undelegate
Undelegate funds from a validator
This function is overridden to add pausable functionality and emit UndelegatedV2
The undelegation ID can be retrieved from the UndelegatedV2 event or via getUndelegation()
function undelegate(address validator, uint256 amount) public virtual override whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
validator | address | The validator to undelegate from |
amount | uint256 | The amount to undelegate |
deregisterValidator
Deregister a validator
This function is overridden to add pausable functionality
and to ensure that the validator’s delegatedAmount is not updated until withdrawal
delegatedAmount represents the no. of tokens that have been delegated to a validator, even if it’s not participating in consensus
emits ValidatorExitV2 instead of ValidatorExit
function deregisterValidator() public virtual override whenNotPaused;
registerValidatorV2
Register a validator in the stake table
This function is overridden to add pausable functionality
and to add schnorrSig validation
function registerValidatorV2(
BN254.G2Point memory blsVK,
EdOnBN254.EdOnBN254Point memory schnorrVK,
BN254.G1Point memory blsSig,
bytes memory schnorrSig,
uint16 commission,
string memory metadataUri
) external virtual whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
blsVK | BN254.G2Point | The BLS verification key |
schnorrVK | EdOnBN254.EdOnBN254Point | The Schnorr verification key |
blsSig | BN254.G1Point | The BLS signature that authenticates the BLS VK |
schnorrSig | bytes | The Schnorr signature that authenticates the Schnorr VK |
commission | uint16 | in % with 2 decimals, from 0.00% (value 0) to 100% (value 10_000) |
metadataUri | string | The metadata URI for the validator |
updateConsensusKeysV2
Update the consensus keys of a validator
This function is overridden to add pausable functionality
and to add schnorrSig validation
function updateConsensusKeysV2(
BN254.G2Point memory blsVK,
EdOnBN254.EdOnBN254Point memory schnorrVK,
BN254.G1Point memory blsSig,
bytes memory schnorrSig
) public virtual whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
blsVK | BN254.G2Point | The new BLS verification key |
schnorrVK | EdOnBN254.EdOnBN254Point | The new Schnorr verification key |
blsSig | BN254.G1Point | The BLS signature that authenticates the blsVK |
schnorrSig | bytes | The Schnorr signature that authenticates the schnorrVK |
updateCommission
Update the commission rate for a validator
- Only one commission increase per minCommissionIncreaseInterval is allowed.
- The commission increase cannot exceed maxCommissionIncrease. These limits protect stakers from sudden large commission increases, particularly by exiting validators.
function updateCommission(uint16 newCommission) external virtual whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
newCommission | uint16 | The new commission rate in % with 2 decimals (0 to 10_000) |
updateMetadataUri
Update the metadata URI for a validator
The metadata URI is NOT stored on-chain. Off-chain indexers must listen to the MetadataUriUpdated event to track the current URI. URIs should be kept reasonably short for gas efficiency (max 2048 bytes). Only the validator (msg.sender) can update their own metadata URI.
No format validation is performed on the URI - any string within length limits (including empty string) is accepted. Consumers should validate URI format and accessibility off-chain.
function updateMetadataUri(string memory metadataUri) external virtual whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
metadataUri | string | The new metadata URI |
setMinCommissionUpdateInterval
Set the minimum interval between commission updates
function setMinCommissionUpdateInterval(uint256 newInterval)
external
virtual
onlyRole(DEFAULT_ADMIN_ROLE);
Parameters
| Name | Type | Description |
|---|---|---|
newInterval | uint256 | The new minimum interval in seconds |
setMaxCommissionIncrease
Set the maximum commission increase allowed per update
function setMaxCommissionIncrease(uint16 newMaxIncrease)
external
virtual
onlyRole(DEFAULT_ADMIN_ROLE);
Parameters
| Name | Type | Description |
|---|---|---|
newMaxIncrease | uint16 | The new maximum increase in basis points (e.g., 500 = 5%) |
_initializeCommissions
Initialize validator commissions during V2 migration
This function is used to retroactively initialize commission storage for validators that were registered before the V2 upgrade. On decaf, this will be called with current commission values read from L1 events. On mainnet, this will be called with an empty array since there are no pre-existing validators.
function _initializeCommissions(InitialCommission[] calldata initialCommissions) private;
Parameters
| Name | Type | Description |
|---|---|---|
initialCommissions | InitialCommission[] | Array of InitialCommission structs containing validator addresses and their commissions |
_initializeActiveStake
Initialize the active stake in the contract
function _initializeActiveStake(uint256 initialActiveStake) private;
Parameters
| Name | Type | Description |
|---|---|---|
initialActiveStake | uint256 | The initial active stake in the contract |
validateMetadataUri
Validate metadata URI length
Public view function to allow external validation before transaction submission
function validateMetadataUri(string memory metadataUri) public pure;
Parameters
| Name | Type | Description |
|---|---|---|
metadataUri | string | The metadata URI to validate |
updateExitEscrowPeriod
Update the exit escrow period
This function ensures that the exit escrow period is within the valid range (MIN_EXIT_ESCROW_PERIOD to MAX_EXIT_ESCROW_PERIOD). However, governance MUST set a value that ensures funds are held until they are no longer staked in Espresso, accounting for validator exit time and slashing evidence submission windows. This function is not pausable so that governance can perform emergency updates in the presence of system upgrades.
function updateExitEscrowPeriod(uint64 newExitEscrowPeriod)
external
virtual
onlyRole(DEFAULT_ADMIN_ROLE);
Parameters
| Name | Type | Description |
|---|---|---|
newExitEscrowPeriod | uint64 | The new exit escrow period |
getUndelegation
Get details of an undelegation for a (validator, delegator) pair
function getUndelegation(address validator, address delegator)
external
view
returns (uint64 id, uint256 amount, uint256 unlocksAt);
Parameters
| Name | Type | Description |
|---|---|---|
validator | address | Address of the validator |
delegator | address | Address of the delegator |
Returns
| Name | Type | Description |
|---|---|---|
id | uint64 | Unique ID of the undelegation |
amount | uint256 | Amount of tokens undelegated |
unlocksAt | uint256 | Timestamp when tokens can be claimed |
_hashSchnorrKey
function _hashSchnorrKey(EdOnBN254.EdOnBN254Point memory schnorrVK)
internal
pure
returns (bytes32);
ensureNewKeys
Ensure that the BLS and Schnorr keys are not already used
function ensureNewKeys(BN254.G2Point memory blsVK, EdOnBN254.EdOnBN254Point memory schnorrVK)
internal
view;
Parameters
| Name | Type | Description |
|---|---|---|
blsVK | BN254.G2Point | The BLS verification key |
schnorrVK | EdOnBN254.EdOnBN254Point | The Schnorr verification key |
registerValidator
Deprecate previous registration function
This function is overridden to revert with a DeprecatedFunction error
users must call registerValidatorV2 instead
function registerValidator(
BN254.G2Point memory,
EdOnBN254.EdOnBN254Point memory,
BN254.G1Point memory,
uint16
) external pure override;
updateConsensusKeys
Deprecate previous updateConsensusKeys function
This function is overridden to revert with a DeprecatedFunction error
users must call updateConsensusKeysV2 instead
function updateConsensusKeys(
BN254.G2Point memory,
EdOnBN254.EdOnBN254Point memory,
BN254.G1Point memory
) external pure override;
setMinDelegateAmount
Set the minimum delegate amount
function setMinDelegateAmount(uint256 newMinDelegateAmount)
external
virtual
onlyRole(DEFAULT_ADMIN_ROLE);
Parameters
| Name | Type | Description |
|---|---|---|
newMinDelegateAmount | uint256 | The new minimum delegate amount in wei |
_authorizeUpgrade
Authorize an upgrade to a new implementation
This function is overridden to use AccessControl instead of Ownable Only addresses with DEFAULT_ADMIN_ROLE can authorize upgrades
function _authorizeUpgrade(address newImplementation)
internal
virtual
override
onlyRole(DEFAULT_ADMIN_ROLE);
Parameters
| Name | Type | Description |
|---|---|---|
newImplementation | address | The address of the new implementation |
Events
ValidatorRegisteredV2
A validator is registered in the stake table
the blsSig and schnorrSig are validated by the Espresso Network
event ValidatorRegisteredV2(
address indexed account,
BN254.G2Point blsVK,
EdOnBN254.EdOnBN254Point schnorrVK,
uint16 commission,
BN254.G1Point blsSig,
bytes schnorrSig,
string metadataUri
);
ConsensusKeysUpdatedV2
A validator updates their consensus keys
the blsSig and schnorrSig are validated by the Espresso Network
event ConsensusKeysUpdatedV2(
address indexed account,
BN254.G2Point blsVK,
EdOnBN254.EdOnBN254Point schnorrVK,
BN254.G1Point blsSig,
bytes schnorrSig
);
ExitEscrowPeriodUpdated
The exit escrow period is updated
event ExitEscrowPeriodUpdated(uint64 newExitEscrowPeriod);
CommissionUpdated
A validator updates their commission rate
the timestamp is emitted to simplify processing in the GCL
event CommissionUpdated(
address indexed validator, uint256 timestamp, uint16 oldCommission, uint16 newCommission
);
Parameters
| Name | Type | Description |
|---|---|---|
validator | address | The address of the validator |
timestamp | uint256 | The timestamp of the update |
oldCommission | uint16 | |
newCommission | uint16 | The new commission rate |
MinCommissionUpdateIntervalUpdated
The minimum commission update interval is updated
event MinCommissionUpdateIntervalUpdated(uint256 newInterval);
Parameters
| Name | Type | Description |
|---|---|---|
newInterval | uint256 | The new minimum update interval in seconds |
MaxCommissionIncreaseUpdated
The maximum commission increase is updated
event MaxCommissionIncreaseUpdated(uint16 newMaxIncrease);
Parameters
| Name | Type | Description |
|---|---|---|
newMaxIncrease | uint16 | The new maximum commission increase in basis points |
UndelegatedV2
A delegator undelegated funds from a validator (V2 with unlocksAt and undelegationId)
event UndelegatedV2(
address indexed delegator,
address indexed validator,
uint64 indexed undelegationId,
uint256 amount,
uint256 unlocksAt
);
Parameters
| Name | Type | Description |
|---|---|---|
delegator | address | The address of the delegator |
validator | address | The address of the validator |
undelegationId | uint64 | Unique identifier for this undelegation |
amount | uint256 | The amount undelegated |
unlocksAt | uint256 | The timestamp when the funds can be claimed |
WithdrawalClaimed
A delegator claimed an undelegation (V2 with undelegationId)
event WithdrawalClaimed(
address indexed delegator,
address indexed validator,
uint64 indexed undelegationId,
uint256 amount
);
Parameters
| Name | Type | Description |
|---|---|---|
delegator | address | The address of the delegator |
validator | address | The address of the validator |
undelegationId | uint64 | Unique identifier for this undelegation |
amount | uint256 | The amount claimed |
ValidatorExitClaimed
A delegator claimed funds after validator exit
event ValidatorExitClaimed(
address indexed delegator, address indexed validator, uint256 amount
);
Parameters
| Name | Type | Description |
|---|---|---|
delegator | address | The address of the delegator |
validator | address | The address of the validator |
amount | uint256 | The amount claimed |
ValidatorExitV2
A validator initiated an exit (V2 with unlocksAt)
event ValidatorExitV2(address indexed validator, uint256 unlocksAt);
Parameters
| Name | Type | Description |
|---|---|---|
validator | address | The address of the validator |
unlocksAt | uint256 | The timestamp when delegators can claim their funds |
MetadataUriUpdated
A validator updated their metadata URI
event MetadataUriUpdated(address indexed validator, string metadataUri);
Parameters
| Name | Type | Description |
|---|---|---|
validator | address | The address of the validator |
metadataUri | string | The new metadata URI |
MinDelegateAmountUpdated
The minimum delegate amount is updated
event MinDelegateAmountUpdated(uint256 newMinDelegateAmount);
Parameters
| Name | Type | Description |
|---|---|---|
newMinDelegateAmount | uint256 | The new minimum delegate amount in wei |
Errors
InvalidSchnorrSig
The Schnorr signature is invalid (either the wrong length or the wrong key)
error InvalidSchnorrSig();
DeprecatedFunction
The function is deprecated as it was replaced by a new function
error DeprecatedFunction();
CommissionUpdateTooSoon
The commission update is too soon after the last update
error CommissionUpdateTooSoon();
CommissionIncreaseExceedsMax
The commission increase exceeds the maximum allowed increase
error CommissionIncreaseExceedsMax();
CommissionUnchanged
The commission value is unchanged
error CommissionUnchanged();
InvalidRateLimitParameters
The rate limit parameters are invalid
error InvalidRateLimitParameters();
CommissionAlreadyInitialized
The validator commission has already been initialized
error CommissionAlreadyInitialized(address validator);
InitialActiveStakeExceedsBalance
The initial active stake exceeds the balance of the contract
error InitialActiveStakeExceedsBalance();
SchnorrKeyAlreadyUsed
The Schnorr key has been previously registered in the contract.
error SchnorrKeyAlreadyUsed();
DefaultAdminCannotBeRevoked
Attempted to revoke DEFAULT_ADMIN_ROLE which would break single-admin governance
error DefaultAdminCannotBeRevoked();
DefaultAdminCannotBeRenounced
Attempted to renounce DEFAULT_ADMIN_ROLE which would break single-admin governance
error DefaultAdminCannotBeRenounced();
NoUndelegationFound
No undelegation exists for the given validator and delegator
error NoUndelegationFound();
InvalidMetadataUriLength
The metadata URI exceeds maximum allowed length
error InvalidMetadataUriLength();
DelegateAmountTooSmall
The delegate amount is too small
error DelegateAmountTooSmall();
MinDelegateAmountTooSmall
The minimum delegate amount is too small
error MinDelegateAmountTooSmall();
Structs
CommissionTracking
Struct for tracking validator commission and last increase time
struct CommissionTracking {
uint16 commission;
uint256 lastIncreaseTime;
}
InitialCommission
Struct for initializing validator commissions during migration
struct InitialCommission {
address validator;
uint16 commission;
}