Skip to main content

RegenStaker

Git Source

Inherits: RegenStakerBase

Title: RegenStaker

Author: Golem Foundation

Staking contract with voting delegation support via surrogates

Extends RegenStakerBase to support IERC20Staking tokens with voting/delegation capabilities

VARIANT COMPARISON:

FeatureRegenStakerWithout Surrogate
Delegation SupportFullNone
Surrogate PatternPer UserContract = Surrogate
Token CustodySurrogatesContract Directly
Voting PowerDelegatedLocked in Contract
Gas (First Delegatee)~300k~100k
Gas (Subsequent)~100k~100k
ComplexityHigherLower
Use CaseGovernanceSimple Staking

DELEGATION MECHANISM:

  1. User stakes tokens and specifies delegatee
  2. Contract deploys/fetches DelegationSurrogateVotes for that delegatee
  3. Tokens transferred to surrogate (not main contract)
  4. Surrogate automatically delegates voting power to delegatee
  5. Delegatee can use voting power in governance
  6. On unstake, tokens withdrawn from surrogate back to user

SURROGATE PATTERN:

  • One surrogate per delegatee (not per user)
  • Deployed on-demand via CREATE2 (deterministic addresses)
  • Surrogates are simple: hold tokens, delegate votes
  • Multiple users can share same surrogate (same delegatee)

GAS CONSIDERATIONS:

  • First use of delegatee: ~250k-350k gas (deploys surrogate)
  • Subsequent uses: ~100k gas (reuses existing surrogate)
  • Pre-deploy surrogates for common delegatees during low gas

WHEN TO USE:

  • Token: IERC20Staking (ERC20 + staking + delegation)
  • Need: Users want to delegate voting power while staked
  • Example: GLM token staking with governance delegation

WHEN NOT TO USE:

  • Token: Simple ERC20 (no voting)
  • Don't need delegation
  • Want to minimize gas costs

Use RegenStakerWithoutDelegateSurrogateVotes instead.

SECURITY:

  • Surrogates deployed via CREATE2 (deterministic, verifiable)
  • Surrogates cannot be controlled by delegatee (just delegation target)
  • Tokens safe in surrogates (only contract can withdraw)

Notes:

Related pages

Quick Start — What Matters Most

Community members use this to stake tokens and earn rewards while participating in allocation decisions.

Key functions to understand:

  • stake — Deposit tokens and specify a delegatee for voting power
  • unstake — Withdraw staked tokens
  • claimReward — Claim earned staking rewards
  • contribute — Support projects directly (if enabled)

State Variables

_surrogates

Mapping of delegatee addresses to their surrogate contracts

One surrogate per delegatee, shared by all users delegating to that address

mapping(address => DelegationSurrogate) private _surrogates

VOTING_TOKEN

The voting token interface for delegation operations

Immutable reference to the staking token with voting capabilities

IERC20Delegates public immutable VOTING_TOKEN

Functions

constructor

Constructor for the RegenStaker contract.

constructor(
IERC20 _rewardsToken,
IERC20Staking _stakeToken,
IEarningPowerCalculator _earningPowerCalculator,
uint256 _maxBumpTip,
address _admin,
uint128 _rewardDuration,
uint128 _minimumStakeAmount,
IAddressSet _stakerAllowset,
IAddressSet _stakerBlockset,
AccessMode _stakerAccessMode,
IAddressSet _allocationMechanismAllowset
)
RegenStakerBase(
_rewardsToken,
IERC20(address(_stakeToken)),
_earningPowerCalculator,
_maxBumpTip,
_admin,
_rewardDuration,
_minimumStakeAmount,
_stakerAllowset,
_stakerBlockset,
_stakerAccessMode,
_allocationMechanismAllowset,
"RegenStaker"
);

Parameters

NameTypeDescription
_rewardsTokenIERC20Token used to reward contributors
_stakeTokenIERC20StakingToken used for staking (must implement IERC20Staking and IERC20Permit)
_earningPowerCalculatorIEarningPowerCalculatorEarning power calculator address
_maxBumpTipuint256Maximum bump tip in reward token base units
_adminaddressAdmin address (TRUSTED)
_rewardDurationuint128Duration for reward distribution in seconds
_minimumStakeAmountuint128Minimum stake required in stake token base units
_stakerAllowsetIAddressSetAllowset for ALLOWSET mode (can be address(0))
_stakerBlocksetIAddressSetBlockset for BLOCKSET mode (can be address(0))
_stakerAccessModeAccessModeStaker access mode (NONE, ALLOWSET, or BLOCKSET)
_allocationMechanismAllowsetIAddressSetAllowset of approved allocation mechanisms (SECURITY CRITICAL) Only audited and trusted allocation mechanisms should be in the allowset. Users contribute funds to these mechanisms and may lose funds if mechanisms are malicious.

surrogates

function surrogates(address _delegatee) public view override returns (DelegationSurrogate);

predictSurrogateAddress

Predicts the deterministic address of a surrogate for a delegatee

Uses CREATE2 address calculation (EIP-1014) Formula: address = last 20 bytes of keccak256(0xff ++ deployer ++ salt ++ initCodeHash) COMPONENTS:

  • deployer: address(this) (RegenStaker contract)
  • salt: keccak256(delegatee address)
  • initCodeHash: keccak256(DelegationSurrogateVotes creation code + constructor args) USE CASES:
  • Predict address before deployment
  • Verify surrogate addresses off-chain
  • Pre-fund surrogates before first use
function predictSurrogateAddress(address _delegatee) public view returns (address);

Parameters

NameTypeDescription
_delegateeaddressAddress that will receive delegated voting power

Returns

NameTypeDescription
<none>addresspredicted Predicted address of the surrogate contract

getDelegateeFromSurrogate

Returns the delegatee that a surrogate delegates to

Queries the voting token to check delegation Returns address(0) if surrogate is invalid or doesn't delegate

function getDelegateeFromSurrogate(address _surrogate) external view returns (address);

Parameters

NameTypeDescription
_surrogateaddressSurrogate contract address to query

Returns

NameTypeDescription
<none>addressdelegatee Address receiving the voting power (or address(0))

_fetchOrDeploySurrogate

Fetches existing surrogate or deploys new one for a delegatee

Core function handling surrogate lifecycle FLOW:

  1. Check if surrogate exists for delegatee
  2. If exists: Return existing (cheap, ~5k gas)
  3. If not: Deploy new surrogate via CREATE2 (~300k gas)
  4. Store surrogate in mapping
  5. Emit SurrogateDeployed event GAS COSTS:
  • First use (deploy): ~250k-350k gas
  • Subsequent uses (fetch): ~5k gas (SLOAD) OPTIMIZATION: Pre-deploy surrogates for common delegatees during low gas periods:
// Off-peak gas optimization
regenStaker._fetchOrDeploySurrogate(popularDelegatee);

CREATE2 BENEFITS:

  • Deterministic addresses (can predict before deploy)
  • Prevents duplicate surrogates for same delegatee
  • Verifiable off-chain
function _fetchOrDeploySurrogate(address _delegatee) internal override returns (DelegationSurrogate _surrogate);

Parameters

NameTypeDescription
_delegateeaddressAddress that will receive voting power

Returns

NameTypeDescription
_surrogateDelegationSurrogateAddress of surrogate contract (existing or newly deployed)

Events

SurrogateDeployed

Emitted when a new delegation surrogate is deployed

event SurrogateDeployed(address indexed delegatee, address indexed surrogate);

Parameters

NameTypeDescription
delegateeaddressAddress that receives voting power
surrogateaddressAddress of deployed surrogate contract