BuildersV4
Overview
The BuildersV4
protocol is an on-chain coordination layer designed for distributing MOR token rewards to subnet builders in a scalable and fair manner. It allows anyone to create a Subnet with specific staking parameters and enables users to stake MOR tokens under a particular Subnet. Rewards are calculated globally and distributed to Subnets based on their effective contribution, determined through staked amounts.
Each Subnet is identified by a unique ID derived from its name and the chain ID, allowing for identical Subnet names across multiple blockchains (v1 and v2 Subnets will have previous ID). Subnet builders (admins) and subnet claim admin are the only ones authorized to claim MOR rewards for their Subnets, while users’ rewards are handled off-chain by the builders. The reward calculation is powered by an external emission curve (RewardPool
) and uses a rate model to determine distribution over time.
Unlike previous versions, v4 removes virtual deposits and multipliers, simplifying staking logic and removing dependency on the claim lock end. Additionally, the system introduces a networkShare
parameter to control how much of the RewardPool
output flows to Builders overall.
Key Features
Subnet creation and configuration: anyone can create a pool with custom parameters; the builder (admin) is assigned at creation.
User staking: users stake tokens into any subnet.
Subnet-controlled reward claiming: only the Subnet admin or Subnet claim admin can claim the MOR rewards, enabling flexible distribution outside the contract scope.
Reward calculation: uses a dynamic rate updated with each user action and proportional to the protocol-wide deposits.
Fee system: integrated with
FeeConfig
for applying customizable claim and creation fees.Upgradeable and permissioned: built with UUPS and Ownable patterns for controlled upgrades and ownership-based access.
Storage
feeConfig
Address of the FeeConfig
contract used to calculate protocol fees.
address public feeConfig;
buildersTreasury
Address of the BuildersTreasury
contract which stores and distributes reward tokens.
address public buildersTreasury;
depositToken
Address of the MOR token users deposit into Subnets.
address public depositToken;
unusedStorage1_V4Update (old editPoolDeadline)
The time window (in seconds) before the pool starts, during which pool parameters can still be edited by the pool admin. Deprecated in v4.
uint128 public editPoolDeadline;
minimalWithdrawLockPeriod
Minimum duration (in seconds) after a deposit during which withdrawals are locked.
uint256 public minimalWithdrawLockPeriod;
allSubnetsData (old totalPoolData)
Aggregated data for all Subnets pools in the system.
AllSubnetsData public allSubnetsData;
struct TotalPoolData {
uint256 distributedRewards;
uint256 rate;
uint256 totalDeposited;
uint256 totalVirtualDeposited;
}
distributedRewards
Total amount of rewards distributed across all pools. Wei.
rate
The current reward rate
totalDeposited
Total tokens deposited without applying any multiplier. Wei.
totalVirtualDeposited
Total tokens deposited with multiplier (used in reward calculations). Wei
subnets (old builderPools)
Mapping of subnetID
to Subnet configuration.
mapping(bytes32 subnetId => Subnet) public subnets;
struct Subnet {
string name;
address admin;
uint128 unusedStorage1_V4Update;
uint128 withdrawLockPeriodAfterDeposit;
uint128 unusedStorage2_V4Update;
uint256 minimalDeposit;
address claimAdmin;
}
name
The name of the Subnet.
admin
The address of the Subnet administrator.
unusedStorage1_V4Update (old poolStart)
Timestamp when the pool becomes active. Deprecated in v4.
withdrawLockPeriodAfterDeposit
Time period after deposit during which withdrawal is locked. Seconds.
unusedStorage2_V4Update (old claimLockEnd)
Timestamp after which rewards can be claimed by the Subnets admin. Seconds. Deprecated in v4.
minimalDeposit
Minimum amount a user must deposit to participate. Wei.
claimAdmin
This address can claim the Subnet rewards against admin
.
subnetsData (old buildersPoolData)
Mapping of pool ID to the current dynamic pool state.
mapping(bytes32 subnetId => SubnetData) public subnetsData;
struct SubnetData {
uint128 unusedStorage1_V4Update;
uint256 deposited;
uint256 unusedStorage2_V4Update;
uint256 rate;
uint256 pendingRewards;
}
unusedStorage1_V4Update (old lastDeposit)
Timestamp in seconds of the last deposit into the pool. Deprecated in v4.
deposited
Total amount deposited MOR. Wei.
unusedStorage2_V4Update (old virtualDeposited)
Total amount deposited with multipliers applied. Wei. Deprecated in v4.
rate
Current reward rate for the Subnet
pendingRewards
Number of rewards accrued to the Subnet. Is not the final reward at a given time. Used for internal calculations. Wei.
usersData
Mapping of user address and pool ID to their user-specific data.
mapping(address => mapping(bytes32 => UserData)) public usersData;
struct UserData {
uint128 lastDeposit;
uint128 unusedStorage1_V4Update;
uint256 deposited;
uint256 unusedStorage2_V4Update;
}
lastDeposit
Timestamp in seconds of the user's last deposit.
unusedStorage1_V4Update ( old claimLockStart)
Timestamp when the user activated the reward lock. Seconds. Deprecated in v4.
deposited
Total tokens the user deposited (raw amount). Wei.
unusedStorage2_V4Update (old virtualDeposited)
Tokens deposited by user with multiplier applied. Wei. Deprecated in v4.
rewardPool
The address of the RewardPool
contract address.
address public rewardPool;
subnetCreationFeeAmount
This value in wei is taken from the tx sender when the Subnet created.
uint256 public subnetCreationFeeAmount;
networkShare
The networkShare
is the share of the network rewards that will be distributed to Subnets, e.g. 100% = 10^25
. If global reward curve return X
amount of rewards, then all Subnets will * receive X * networkShare / 10^25
uint256 public networkShare;
networkShareOwner
This address can change the networkShare
value.
address public networkShareOwner;
subnetsMetadata
Contain the metadata about Subnets
mapping(bytes32 subnetId => SubnetMetadata) public subnetsMetadata;
struct SubnetMetadata {
string slug;
string description;
string website;
string image;
}
slug
The Subnet slug string.
description
The Subnet description string.
website
The Subnet website string.
image
The Subnet image link.
allSubnetsDataV4
The variable that stores all Subnets data, addition for allSubnetsData
.
AllSubnetsDataV4 public allSubnetsDataV4;
struct AllSubnetsDataV4 {
uint256 distributedRewards;
uint256 undistributedRewards;
uint256 claimedRewards;
uint128 lastUpdate;
}
distributedRewards
The amount of rewards that calculated and virtually distributed between Subnets. Wei.
undistributedRewards
The amount of rewards that calculated and stored for the contract owner. Wei
claimedRewards
The total amount of claimed rewards. Wei.
lastUpdate
The AllSubnetsData.rate
last update timestamp.
Fee oprations
The lables for fee operations, uses for fee and treasury receiving in the FeeConfig
contract. FEE_SUBNET_CREATE
uses only treasury address from the FeeConfig
contract.
// bytes32 private constant FEE_WITHDRAW_OPERATION = "withdraw";
bytes32 public constant FEE_CLAIM_OPERATION = "claim";
bytes32 public constant FEE_SUBNET_CREATE = "buildersV4.fee.subnet.create";
Write functions for the contract owner
BuildersV4_init
Initializes the contract with essential parameters and configuration contracts. This function must be called once after deployment.
function BuildersV4_init(
address depositToken_,
address feeConfig_,
address treasury_,
address rewardPool_,
address networkShareOwner_,
uint256 minimalWithdrawLockPeriod_
) external initializer
depositToken_
Address of the token that users will deposit in builder pools. MOR token.
feeConfig_
Address of the FeeConfig
contract used to calculate protocol fees.
treasury_
Address of the BuildersTreasuryV2
contract used to store and distribute rewards.
rewardPool_
Address of the RewardPool
contract.
networkShareOwner_
The address wich can edit the networkShare
.
minimalWithdrawLockPeriod_
Minimum lock duration after deposit in seconds before users can withdraw staked MOR.
setFeeConfig
Sets the address of the FeeConfig
contract.
function setFeeConfig(address feeConfig_) public onlyOwner
feeConfig_
Address of a contract that implements IFeeConfig
setBuildersTreasury
Sets the address of the BuildersTreasuryV2
contract.
function setBuildersTreasury(address buildersTreasury_) public onlyOwner
buildersTreasury_
Address of a contract that implements IBuildersTreasury
setMinimalWithdrawLockPeriod
Sets the minimum lock period that must pass before a user can withdraw MOR after depositing.
function setMinimalWithdrawLockPeriod(
uint256 minimalWithdrawLockPeriod_
) public onlyOwner
minimalWithdrawLockPeriod_
Minimum lock period (in seconds) after deposit before withdrawal
setRewardPool
Sets the address of the RewardPool
contract.
function setRewardPool(address rewardPool_) external onlyOwner;
rewardPool_
Address of the RewardPool
contract to set.
setNetworkShareOwner
Sets the address that is authorized to change the networkShare value.
function setNetworkShareOwner(address networkShareOwner_) external onlyOwner;
networkShareOwner_
Address that will be allowed to update the networkShare
value.
setNetworkShare
Sets the percentage of rewards allocated to all Subnets.
function setNetworkShare(uint256 networkShare_) external onlyOwner;
networkShare_
Percentage value where 100% = 1e25. Only owner or networkShareOwner
.
setSubnetCreationFeeAmount
Sets the fee amount (in MOR tokens) required to create a Subnet.
function setSubnetCreationFeeAmount(
uint256 subnetCreationFeeAmount_
) external onlyOwner;
subnetCreationFeeAmount_
MOR amount in wei.
Write functions
createBuilderPool
Creates a new Subnet with specific parameters. If subnetCreationFee
set, it will be charged from the tx caller.
function createSubnet(
Subnet calldata subnet_,
SubnetMetadata calldata metadata_
) external;
subnet_
The Subnet
struct.
metadata_
The SubnetMetadata
struct.
editSubnet
Edits an existing Subnet's main configuration. The caller should be the Subnet admin.
function editSubnet(
bytes32 subnetId_,
Subnet calldata newSubnet_
) external onlySubnetOwner(subnetId_)
subnetId_
ID of the Subnet.
newSubnet_
The Subnet
struct.
editSubnet
Edits an existing Subnet's metadata configuration. The caller should be the Subnet admin.
function editSubnetMetadata(
bytes32 subnetId_,
SubnetMetadata calldata metadata_
) public onlySubnetOwner(subnetId_)
subnetId_
ID of the Subnet.
metadata_
The SubnetMetadata
struct.
deposit
Allows a user to deposit tokens into a specific Subnet.
function deposit(bytes32 subnetId_, uint256 amount_) external
subnetId_
ID of the Subnet.
amount_
Amount of tokens to deposit. Wei.
withdraw
Allows a user to withdraws tokens from a specific Subnet.
function withdraw(bytes32 subnetId_, uint256 amount_) external
subnetId_
ID of the Subnet.
amount_
Amount of tokens to withdraw. Wei.
claim
Allows the Subnet admin or Subnet claim admin to claim the accumulated MOR rewards.
function claim(bytes32 subnetId_, address receiver_) external
subnetId_
ID of the Subnet.
receiver_
Address to receive the claimed MOR rewards
Read functions
getCurrentSubnetsRewards
The function calculates the potential claim reward amount for ALL Subnets at the current moment in time, based on the current contract parameters. It estimates the unclaimed rewards that would be distributed if a claim were made now.
function getCurrentSubnetsRewards() external view returns (uint256)
getCurrentSubnetRewards
The function calculates the potential claim reward amount for the SPECIFIC Subnet at the current moment in time, based on the current contract parameters. It estimates the unclaimed rewards that would be distributed if a claim were made now.
function getCurrentSubnetRewards(
bytes32 subnetId_
) external view returns (uint256)
subnetId_
ID of the Subnet.
getSubnetId
Computes the unique ID of a Subnet based on its name and chain ID.
function getSubnetId(string memory subnetName_) public view returns (bytes32)
subnetName_
Name of the Subnet
getSubnetIdOld
Computes the unique ID of a Subnet based on its name. Subnets created in the v1 and v2 used this ID.
function getSubnetIdOld(string memory subnetName_) public view returns (bytes32)
subnetName_
Name of the Subnet
supportsInterface
Used for interface detection (ERC165). Returns true if the contract supports a specific interfaceId_
. Supports IBuildersV2
, IERC165
.
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
version
Returns the current version of the contract.
function version() external pure returns (uint256
Last updated
Was this helpful?