Valocracy
Valocracy is a novel social, economic, and political framework that leverages blockchain technology to create new forms of organizations with the goal of empowering communities along with their individuals and their combined efforts. It aims to provide a structured approach to building more efficient and fair decentralized organizations.
Core Principles
-
Tokenized Effort: Effort is tokenized through two distinct tokens:
- Governance Power: Implemented as ERC20Votes with Soulbound Degradable Governance (SDG) standard, ensuring voting power cannot be transferred and decays over time without active participation
- Economic Power: Implemented as ERC20 with ERC4626 vault interface, representing shares of the underlying treasury asset
-
Valueholder Concept: Blurs the distinction between shareholders and laborers, allowing individuals to decide when to act as paid laborers or shareholders.
-
Time-Based Governance: Governance power follows a dynamic curve:
- Stable Period: Initial period where governance power remains constant
- Decay Period: Following the stable period, governance power gradually decreases over time
- This mechanism ensures active participation while preventing governance attacks
Smart Contracts
The project consists of several core smart contracts:
- Valocracy.sol: The main contract implementing ERC20Votes with SDG.
- Treasury.sol: Manages the collective treasury and economic power distribution using ERC20
- SDG.sol: Implements the IERC7787 for Soulbound Degradable Governance
- Interfaces/: Contains the core interfaces for the system
Documentation and Coverage
- Smart Contract Documentation: Detailed documentation of our smart contracts can be found at https://resources.valocracy.xyz/book/
- Test Coverage: View our test coverage reports at https://resources.valocracy.xyz/coverage/
Learn More
For a deeper understanding of Valocracy's principles and vision, please read our Manifesto.
Contributing
Please see our CONTRIBUTING.md for details on how to contribute to this project.
Contents
IERC7787
Functions
stablePeriod
Returns the grace period duration before the voting units begins decaying. This period is fixed to 90 days. But it can be overridden in derived contracts.
function stablePeriod() external view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The duration of the grace period in seconds. |
decayPeriod
Returns the duration of the decay period during which the voting units decreases. This period is fixed to 90 days. But it can be overridden in derived contracts.
function decayPeriod() external view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The duration of the decay period in seconds. |
accountStats
Returns the raw last participation timestamp of an account without any decay adjustments.
function accountStats(address account) external view returns (uint32);
Errors
TokenSoulbound
Error thrown when attempting to transfer a soulbound token
error TokenSoulbound();
ITreasury
Functions
asset
Returns the address of the single underlying asset token used by the treasury for accounting, depositing, and withdrawing.
function asset() external view returns (address);
Returns
Name | Type | Description |
---|---|---|
<none> | address | The address of the underlying asset token |
totalAssets
Returns the total amount of the single underlying asset that is managed by the treasury.
function totalAssets() external view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The total amount of the underlying asset |
previewWithdraw
Calculates the amount of the underlying asset that would be returned from burning the given amount of shares.
function previewWithdraw(uint256 shares) external view returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
shares | uint256 | The amount of shares to calculate assets for |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The amount of underlying asset that would be returned |
deposit
Deposits the underlying asset into the treasury and mints shares to the receiver. Only callable by the Valocracy contract.
function deposit(address receiver, uint256 shares) external;
Parameters
Name | Type | Description |
---|---|---|
receiver | address | The address that will receive the shares |
shares | uint256 | The amount of shares to mint |
withdraw
Withdraws the underlying asset from the treasury by burning shares. Transfers the corresponding amount of the underlying asset to the receiver.
function withdraw(address receiver, uint256 shares) external;
Parameters
Name | Type | Description |
---|---|---|
receiver | address | The address that will receive the underlying asset |
shares | uint256 | The amount of shares to burn |
Events
Deposit
Emitted when a new deposit of the underlying asset is made.
event Deposit(address indexed receiver, uint256 shares);
Parameters
Name | Type | Description |
---|---|---|
receiver | address | The address that received the shares |
shares | uint256 | The amount of shares minted |
Withdraw
Emitted when a withdrawal of the underlying asset is made.
event Withdraw(address indexed owner, address indexed receiver, uint256 assets, uint256 shares);
Parameters
Name | Type | Description |
---|---|---|
owner | address | The address that burned the shares |
receiver | address | The address that received the underlying asset |
assets | uint256 | The amount of underlying asset withdrawn |
shares | uint256 | The amount of shares burned |
Errors
NotAuthorized
Emitted when a non-authorized account attempts to call a function.
error NotAuthorized(address caller);
IValocracy
Functions
balanceOf
*Returns the balance of an account with decay applied. Implements the EIP-7787 decay mechanism:
- Full balance during stable period
- Linear decay during decay period
- Zero balance after decay period ends*
function balanceOf(address account) external view returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
account | address | The address to check the balance for |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The current balance with decay applied |
stablePeriod
Returns the stable period duration in seconds.
function stablePeriod() external view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The stable period duration |
decayPeriod
Returns the decay period duration in seconds.
function decayPeriod() external view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The decay period duration |
grantVotingUnits
Grants voting units to the specified account. Only the contract owner can mint new tokens and grant additional voting units. Updates the last participation timestamp to start the stable period.
function grantVotingUnits(address to, uint256 amount) external;
Parameters
Name | Type | Description |
---|---|---|
to | address | The address to grant voting units to |
amount | uint256 | The amount of voting units to grant |
burn
Burns tokens and reduces the voting units associated with the token holder.
function burn(uint256 amount) external;
Parameters
Name | Type | Description |
---|---|---|
amount | uint256 | The amount of tokens to burn |
Events
VotingUnitsGranted
Emitted when voting units are granted to an account.
event VotingUnitsGranted(address indexed account, uint256 amount);
Parameters
Name | Type | Description |
---|---|---|
account | address | The address that received the voting units |
amount | uint256 | The amount of voting units granted |
VotingUnitsBurned
Emitted when voting units are burned.
event VotingUnitsBurned(address indexed account, uint256 amount);
Parameters
Name | Type | Description |
---|---|---|
account | address | The address that burned the voting units |
amount | uint256 | The amount of voting units burned |
Errors
TokenSoulbound
Emitted when attempting to transfer a soulbound token.
error TokenSoulbound();
SDG
Inherits: IERC7787
Author: nomadbitcoin
This contract implements the EIP-7787 standard proposed by Guilherme Neves (@0xneves) and Rafael Castaneda for governance systems where voting power is non-transferable and decays over time. The system ensures that governance power reflects recent and active participation in the ecosystem by implementing a two-phase decay mechanism:
- Stable Period: Voting power remains constant for a fixed duration after each contribution
- Decay Period: After the stable period ends, voting power linearly decays until it reaches zero System Rules:
- Voting power remains stable for the duration of the stable period after each contribution
- After the stable period ends, voting power linearly decays over the decay period
- If no new contributions are made during the decay period, voting power reaches zero
- New contributions reset both the stable and decay periods
- Lost voting power cannot be recovered without new contributions
*This implementation follows the EIP-7787 specification but uses 'stablePeriod' instead of 'gracePeriod' for clarity. The contract provides the core functionality for calculating voting power with time-based degradation. Requirements:
- The contract requires stable period and decay period to be configured
- The contract implements linear decay as specified in EIP-7787*
State Variables
SECONDS_PER_DAY
Number of seconds in a day
uint32 private constant SECONDS_PER_DAY = 86400;
_lastParticipation
Mapping from accounts addresses to their last participation timestamp
mapping(address => uint32) private _lastParticipation;
_stablePeriod
Configuration of the stable and decay periods (in days)
uint32 private _stablePeriod;
_decayPeriod
uint32 private _decayPeriod;
Functions
stablePeriod
Returns the duration of the stable period in days.
function stablePeriod() public view virtual returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The duration of the stable period in days. |
decayPeriod
Returns the duration of the decay period in days.
function decayPeriod() public view virtual returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The duration of the decay period in days. |
accountStats
Returns the raw last participation timestamp of an account without any decay adjustments.
function accountStats(address account) public view virtual returns (uint32);
Parameters
Name | Type | Description |
---|---|---|
account | address | The address to check for last participation |
Returns
Name | Type | Description |
---|---|---|
<none> | uint32 | The timestamp of the last participation |
_updateLastParticipation
Updates the last participation timestamp for an account.
function _updateLastParticipation(address account) internal virtual;
Parameters
Name | Type | Description |
---|---|---|
account | address | The address to update the participation timestamp for |
_setStablePeriod
Sets a new stable period in days
function _setStablePeriod(uint32 stablePeriod_) internal virtual;
Parameters
Name | Type | Description |
---|---|---|
stablePeriod_ | uint32 | The new stable period duration in days |
_setDecayPeriod
Sets a new decay period in days
function _setDecayPeriod(uint32 decayPeriod_) internal virtual;
Parameters
Name | Type | Description |
---|---|---|
decayPeriod_ | uint32 | The new decay period duration in days |
balanceOf
Returns the balance of the account with decay applied.
function balanceOf(address account) public view virtual returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
account | address | The address to check the balance for |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The current balance with decay applied |
Treasury
Inherits: ERC20, ITreasury
Implementation of a single-asset treasury that manages deposits and withdrawals
This contract extends ERC20 to implement a treasury system for a single underlying asset
State Variables
_asset
The single underlying asset token managed by this treasury
IERC20 private immutable _asset;
_valocracy
The Valocracy contract address that controls deposits
address private _valocracy;
Functions
constructor
Initializes the contract by setting a name
and a symbol
for the treasury shares. Also sets the Valocracy contract and the
single underlying asset token.
constructor(IERC20 asset_, address valocracy, string memory name, string memory symbol) ERC20(name, symbol);
Parameters
Name | Type | Description |
---|---|---|
asset_ | IERC20 | The single underlying asset token to be managed |
valocracy | address | The address of the Valocracy contract that controls deposits |
name | string | The name of the treasury shares |
symbol | string | The symbol of the treasury shares |
asset
Returns the address of the single underlying asset token.
function asset() public view virtual returns (address);
Returns
Name | Type | Description |
---|---|---|
<none> | address | The address of the asset token |
totalAssets
Returns the total amount of the single asset held by the treasury.
function totalAssets() public view virtual returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The total balance of the underlying asset |
previewWithdraw
Calculates the amount of the underlying asset that would be returned for burning the given amount of shares. The calculation is based on the proportion of total assets to total shares. For example, if there are 2000 assets and 1000 shares, each share represents 2 assets.
function previewWithdraw(uint256 shares) public view virtual returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
shares | uint256 | The amount of shares to calculate assets for |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The amount of the underlying asset that would be returned |
deposit
Deposits the underlying asset into the treasury and mints shares to the receiver. Only callable by the Valocracy contract.
function deposit(address receiver, uint256 shares) public;
Parameters
Name | Type | Description |
---|---|---|
receiver | address | The address that will receive the shares |
shares | uint256 | The amount of shares to mint |
withdraw
Withdraws the underlying asset from the treasury by burning shares. Transfers the corresponding amount of the underlying asset to the receiver.
function withdraw(address receiver, uint256 shares) public;
Parameters
Name | Type | Description |
---|---|---|
receiver | address | The address that will receive the underlying asset |
shares | uint256 | The amount of shares to burn |
Valocracy
Inherits: ERC20Votes, Ownable, SDG
Implementation of the EIP-7787 Soulbound Degradable Governance standard using ERC20 tokens
This contract extends ERC20Votes to implement non-transferable tokens with decaying voting power
State Variables
SECONDS_PER_DAY
Number of seconds in a day
uint32 private constant SECONDS_PER_DAY = 86400;
_lastParticipation
Mapping from accounts addresses to their last participation timestamp
mapping(address => uint32) private _lastParticipation;
Functions
constructor
Initializes the contract by setting a name
and a symbol
.
Sets default stable and decay periods to 90 days each.
constructor(string memory name, string memory symbol)
ERC20(name, symbol)
ERC20Votes()
Ownable(msg.sender)
EIP712(name, "1");
Parameters
Name | Type | Description |
---|---|---|
name | string | The name of the token |
symbol | string | The symbol of the token |
tokenURI
Returns the token URI for a given token ID.
function tokenURI(uint256 tokenId) public view returns (string memory);
Parameters
Name | Type | Description |
---|---|---|
tokenId | uint256 | The ID of the token |
Returns
Name | Type | Description |
---|---|---|
<none> | string | The token URI |
_update
Overrides the ERC20Votes-_update to make the token soulbound. Only allows minting and burning, prevents transfers between accounts.
function _update(address from, address to, uint256 value) internal virtual override;
Parameters
Name | Type | Description |
---|---|---|
from | address | The address sending the tokens |
to | address | The address receiving the tokens |
value | uint256 | The amount of tokens |
balanceOf
*Returns the balance of account
with decay applied.
Implements the EIP-7787 decay mechanism:
- Full balance during stable period
- Linear decay during decay period
- Zero balance after decay period ends*
function balanceOf(address account) public view override(ERC20, SDG) returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
account | address | The address to check the balance for |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The current balance with decay applied |
_getVotingUnits
Returns the voting units for an account.
function _getVotingUnits(address account) internal view override returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
account | address | The address to check voting units for |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The current voting units |
grantVotingUnits
Grants voting units to the specified account by amount
.
Only the contract owner can mint new tokens and grant additional voting units.
Updates the last participation timestamp to start the stable period.
function grantVotingUnits(address to, uint256 amount) public onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
to | address | The address to grant voting units to |
amount | uint256 | The amount of voting units to grant |
burn
Burns tokens and reduces the voting units associated with the token holder.
function burn(uint256 amount) public virtual;
Parameters
Name | Type | Description |
---|---|---|
amount | uint256 | The amount of tokens to burn |