The Token Days Destroyed (TDD) Staking Module is a smart contract implemented in the Move programming language for Move-based blockchains (e.g., Aptos). It allows users to stake any fungible tokens (FTs) they wish, without requiring prior setup or initialization by an admin for that token type. The module calculates Token Days Destroyed (TDD) based on the amount staked and the number of blocks that have passed since staking.
Users pay for the resources necessary to stake new tokens, and the contract ensures that one user's actions do not affect another user's resources, maintaining resource isolation and security.
The staking contract allows users to stake any cryptocurrency token (CoinType
) they wish, without requiring prior setup or initialization by the admin for that token type. Users can stake and unstake tokens independently for each CoinType
, and the contract maintains separate staking records for each CoinType
per user. The contract tracks the staked amount and token days destroyed (TDD) for each token type individually.
An admin account is responsible for initializing the contract and setting the treasury address where staked tokens are held. The admin can perform emergency withdrawals of tokens not part of the total staked amounts and can transfer admin rights to another address. The contract emits events for staking and unstaking actions for each CoinType
to facilitate tracking and transparency.
Users pay for the resources necessary to stake new CoinType
s, and the contract ensures that one user's actions do not affect another user's resources, maintaining resource isolation and security.
-
Initialization
-
Admin Initialization
- The
initialize_admin
function allows the contract deployer to set up the admin account. - It can only be called once to prevent reinitialization.
- The
-
Configuration Initialization
- The
initialize_config
function allows the admin to set the treasury address where staked tokens are held. - It can only be called once.
- The
-
-
Staking Tokens
-
User-Initiated
CoinType
Staking- Users can stake any
CoinType
without prior admin setup. - The
stake
function checks if the necessary resources for theCoinType
exist, and if not, initializes them. - Users pay for the gas costs associated with resource initialization.
- Users can stake any
-
Stake Function
- Users can stake tokens of different types by calling the
stake
function with the specificCoinType
and amount. - The function transfers the specified amount from the user's account to the treasury address for that token.
- For each
CoinType
, the user has a separateStaker<CoinType>
resource under their address. - The staked amounts and TDD are tracked separately for each
CoinType
. - The total staked amount for each
CoinType
is updated in the global staking info. - A
StakingEvent<CoinType>
is emitted to record the staking action for that token.
- Users can stake tokens of different types by calling the
-
-
Unstaking Tokens
- Unstake Function
- Users can unstake tokens by calling the
unstake
function with the specificCoinType
and amount. - The function transfers the specified amount from the treasury address back to the user's account for that token.
- The user's staked amount and TDD for that
CoinType
are updated accordingly. - The total staked amount for the
CoinType
is updated in the global staking info. - A
StakingEvent<CoinType>
is emitted to record the unstaking action for that token.
- Users can unstake tokens by calling the
- Unstake Function
-
Token Days Destroyed (TDD)
- Per-Token TDD Tracking
- The contract keeps track of TDD separately for each
CoinType
a user stakes. - TDD is calculated based on the amount staked and the duration for which it was staked for each token type.
- Functions like
calculate_token_days_destroyed
operate perCoinType
.
- The contract keeps track of TDD separately for each
- Per-Token TDD Tracking
-
Admin Functions
-
Emergency Withdrawal
- The admin can perform an emergency withdrawal of tokens not part of the total staked amounts.
- The function ensures that the total staked tokens are not affected.
-
Transfer of Admin Rights
- The admin can transfer their rights to a new admin address using the
transfer_admin
function.
- The admin can transfer their rights to a new admin address using the
-
-
Cleanup of Staker Resource
- Cleanup Function
- Users can call
cleanup_staker
with the specificCoinType
to remove theirStaker<CoinType>
resource if their staked amount is zero for that token. - This helps in freeing up storage space when a user no longer has any staked tokens of a particular type.
- Users can call
- Cleanup Function
-
Event Emission
- Per-Token Staking Events
- The contract emits events for staking and unstaking actions separately for each
CoinType
. - Events include the user's address, the amount staked or unstaked, and a flag indicating the action type.
- The contract emits events for staking and unstaking actions separately for each
- Per-Token Staking Events
-
Access Control
-
Admin-Only Functions
- Functions like
initialize_config
,emergency_withdraw
, andtransfer_admin
are restricted to the admin account.
- Functions like
-
User Functions
- Functions like
stake
,unstake
,calculate_token_days_destroyed
,get_staked_amount
, andcleanup_staker
are available to users for eachCoinType
.
- Functions like
-
-
Security Measures
- Assertions and Checks
- The contract includes assertions to prevent invalid states per
CoinType
, such as staking or unstaking zero tokens, or unstaking more than the staked amount. - Arithmetic operations rely on Move's built-in overflow checks.
- Access control checks ensure that only authorized accounts can perform certain actions.
- Type constraints ensure that only valid coin types can be staked.
- The contract includes assertions to prevent invalid states per
- Assertions and Checks
-
Modularity and Extensibility
- Generic Coin Type
- The contract is generic over
CoinType
, allowing it to support staking for different types of tokens.
- The contract is generic over
- Resource Management
- The use of per-token resources for stakers and global staking info ensures proper management and protection of data for each token type.
- Users pay for the resources they initialize, and resource isolation ensures that one user's actions do not affect others.
- Generic Coin Type
-
Implementation:
- The
stake
function now initializesStakingEvents
andGlobalStakingInfo
resources for aCoinType
if they do not exist. - Users pay for the resource creation costs.
- The
-
Security Considerations:
-
Type Constraints:
- The
CoinType
is constrained bystore + CoinStore
, ensuring only valid coin types that implement theCoinStore
trait can be staked. - Risk Mitigated: Prevents users from staking arbitrary types that are not valid coins.
- The
-
Resource Spamming:
- Risk: Users could create numerous resources for different
CoinType
s, consuming storage and potentially affecting network performance. - Mitigation:
- Users pay the gas fees associated with resource creation, providing a financial disincentive for spamming.
- Storage costs in the blockchain platform further discourage unnecessary resource creation.
- Conclusion: The risk is adequately mitigated.
- Risk: Users could create numerous resources for different
-
Interference with Other Users:
- Resources are parameterized by
CoinType
and stored under the user's address (forStaker
) or module address (for global resources). - Risk Mitigated: Users cannot access or modify other users' resources, maintaining resource isolation.
- Resources are parameterized by
-
-
Unstake Function:
- Modified to handle cases where
GlobalStakingInfo
might not exist by initializing it if absent. - Security Consideration: Ensures consistent behavior and prevents potential errors when unstaking tokens that haven't been staked before globally.
- Modified to handle cases where
-
Emergency Withdrawal:
- Adjusted to handle cases where
GlobalStakingInfo
might not exist, assuming total staked is zero in such cases. - Security Consideration: Prevents incorrect calculations of available balance for withdrawal.
- Adjusted to handle cases where
- Admin Functions:
- Functions like
initialize_config
,emergency_withdraw
, andtransfer_admin
still require admin privileges. - Security Consideration: Admin-only functions are protected, and admin rights are not compromised by the changes.
- Functions like
-
Assertions:
- All critical functions include assertions to prevent invalid operations, such as staking zero tokens or unstaking more than the staked amount.
- Security Consideration: Prevents invalid state changes and maintains contract integrity.
-
Overflow Checks:
- Move's built-in overflow checks handle arithmetic operations, ensuring safe calculations.
- Security Consideration: Prevents integer overflows and underflows.
- Per-Token Events:
- Events are correctly emitted for staking and unstaking actions, with
CoinType
parameterization ensuring they are associated with the correct token. - Security Consideration: Event handling is secure and provides transparency.
- Events are correctly emitted for staking and unstaking actions, with
-
User-Paid Resources:
- Users are responsible for paying the gas fees for resource initialization, aligning costs with resource usage.
- Security Consideration: Encourages responsible use and mitigates potential abuse.
-
Resource Isolation:
- Each user's resources are managed independently, with no shared mutable state that could lead to race conditions or interference.
- Security Consideration: Maintains security and data integrity across users.
-
Arbitrary
CoinType
Staking:- Risk: Users might attempt to stake tokens that are malicious or not intended for staking.
- Mitigation:
- The
CoinStore
trait constraint ensures only registered coin types can be staked. - Recommendation: Consider implementing additional validation if necessary, such as checking against a whitelist of approved tokens.
- The
-
Denial-of-Service (DoS) via Resource Creation:
- Risk: Excessive resource creation could strain network resources.
- Mitigation:
- Gas fees and storage costs act as deterrents.
- Recommendation: Monitor resource usage and consider setting limits if necessary.
-
Security of External Calls:
- All external calls are to standard library functions (e.g.,
CoinFramework::transfer
), which are considered secure. - Security Consideration: No vulnerabilities identified related to external calls.
- All external calls are to standard library functions (e.g.,
-
Comprehensive Tests:
- The test suite includes scenarios where users stake multiple
CoinType
s without prior admin setup. - Security Consideration: Testing verifies that the contract behaves correctly under the new functionality.
- The test suite includes scenarios where users stake multiple
-
Edge Cases:
- Tests cover edge cases such as unstaking when resources do not exist and ensure appropriate error handling.
- Security Consideration: Ensures robustness of the contract.
-
Overall Assessment:
- The contract modifications successfully allow users to stake any
CoinType
without prior admin setup while maintaining security. - Resource isolation and type constraints prevent users from affecting other users' resources or staking invalid tokens.
- The contract modifications successfully allow users to stake any
-
Security Posture:
- Strong, with potential risks adequately mitigated through design choices and Move's safety features.
-
Recommendations:
- Optional Enhancements:
- Implement additional validation for
CoinType
if desired. - Monitor resource creation and usage patterns.
- Implement additional validation for
- Documentation:
- Update documentation to reflect the changes and inform users about the ability to stake any
CoinType
. - Provide guidance on acceptable
CoinType
s and any limitations.
- Update documentation to reflect the changes and inform users about the ability to stake any
- Optional Enhancements:
- Users Can Stake Any CoinType: Users can stake any fungible token without prior admin setup, paying for the necessary resources themselves.
- Accurate Tracking of Total Staked Tokens: Introduces a global resource to track the total staked amount for each token type (
CoinType
), updating whenever users stake or unstake tokens. - Configurable Admin Resource: Stores the admin's address in a resource that can be updated via a governance process, allowing for admin transfer functionality.
- Atomic Transactions and Concurrency Control: Ensures staking and unstaking operations are atomic and isolated, with Move's resource model preventing conflicting transactions.
- Reuse of
Staker
Resource: Retains theStaker
resource even when the staked amount reaches zero, providing an optional cleanup function for users. - Enhanced Error Messages: Utilizes descriptive error messages that are accessible and meaningful to users.
- Exclusive Control Over Staked Tokens: Only the staker can withdraw their staked tokens; neither the admin nor the treasury can access them.
- Protection Against Unauthorized Access: Move's resource and access control mechanisms enforce strict ownership rules.
- Admin's Limited Authority: The admin cannot withdraw staked tokens belonging to users; administrative functions are restricted.
- Safe and Atomic Operations: Transactions are atomic, ensuring state changes are fully applied or not at all.
- Accurate Total Staked Tracking: Prevents the admin or treasury from inadvertently accessing staked tokens.
- Concurrency Control: Prevents reentrancy and race conditions.
- User-Paid Resource Creation: Users pay for the resources they initialize, aligning costs with resource usage and discouraging abuse.
- Resource Isolation: Each user's resources are managed independently, maintaining data integrity and security.
README.md
: Project documentation.Move.toml
: Move package configuration file.sources/
: Contains the staking module source code.tests/
: Contains unit tests for the staking module.
- Move CLI: Installed on your machine. Move CLI Installation Guide
- Git: Version control system installed.
- Aptos Node or Network Access: Access to the target blockchain you're deploying to.
git clone https://github.com/your-username/your-github-repo.git
cd your-github-repo
Ensure you have the necessary dependencies specified in Move.toml
.
Compile the Move modules:
move package build
This command compiles the Move modules and checks for any errors.
Execute the unit tests:
move package test
This command runs the unit tests located in the tests/
directory, ensuring that the staking module functions as expected.
To deploy the modules to the blockchain, use the following command:
move package publish --url <node_url> --private-key <your_private_key>
<node_url>
: The URL of the blockchain node you're connecting to.<your_private_key>
: Your private key for the account deploying the module.
Note: Make sure you understand the security implications of using your private key in commands. Consider using environment variables or a secure key management system.
This step only needs to be done once by the admin.
TokenDaysDestroyedStaking::initialize_admin(&admin_signer);
Set the treasury address where staked tokens will be held.
TokenDaysDestroyedStaking::initialize_config(&admin_signer, treasury_address);
Users can stake tokens by calling the stake
function.
TokenDaysDestroyedStaking::stake<CoinType>(&user_signer, amount);
user_signer
: The signer's account of the user staking tokens.CoinType
: The type of token being staked (e.g.,AptosCoin
).amount
: The amount of tokens to stake (must be greater than zero).
Example:
TokenDaysDestroyedStaking::stake<AptosCoin>(&user_signer, 100_000);
Users can unstake tokens and receive them back from the treasury.
TokenDaysDestroyedStaking::unstake<CoinType>(&user_signer, amount);
user_signer
: The signer's account of the user unstaking tokens.CoinType
: The type of token being unstaked.amount
: The amount of tokens to unstake (must be greater than zero).
Example:
TokenDaysDestroyedStaking::unstake<AptosCoin>(&user_signer, 50_000);
Users can calculate their total TDD for a specific CoinType
.
let tdd = TokenDaysDestroyedStaking::calculate_token_days_destroyed<CoinType>(user_address);
user_address
: The address of the user whose TDD is being calculated.tdd
: The returned Token Days Destroyed value (u128
).
Example:
let tdd = TokenDaysDestroyedStaking::calculate_token_days_destroyed<AptosCoin>(user_address);
Users can retrieve their staked amount for a specific CoinType
.
let staked_amount = TokenDaysDestroyedStaking::get_staked_amount<CoinType>(user_address);
staked_amount
: AnOption<u64>
containing the user's staked amount if they have staked tokens.
Example:
let staked_amount = TokenDaysDestroyedStaking::get_staked_amount<AptosCoin>(user_address);
Users can destroy their Staker
resource if they have a zero staked amount for a specific CoinType
.
TokenDaysDestroyedStaking::cleanup_staker<CoinType>(&user_signer);
Example:
TokenDaysDestroyedStaking::cleanup_staker<AptosCoin>(&user_signer);
The admin can transfer admin rights to a new address.
TokenDaysDestroyedStaking::transfer_admin(&admin_signer, new_admin_address);
new_admin_address
: The address of the new admin.
The admin can withdraw tokens not part of the staked balances.
TokenDaysDestroyedStaking::emergency_withdraw<CoinType>(&admin_signer, amount);
CoinType
: The type of token to withdraw.amount
: The amount to withdraw.
Note: The admin cannot withdraw tokens that are part of the staked balances.
The module uses descriptive error messages to help identify issues. Assertions are used to enforce conditions, and Move's built-in error handling will abort transactions if assertions fail.
The module includes unit tests located in the tests/
directory. These tests cover various scenarios, including:
- Staking and unstaking tokens without prior admin setup for the
CoinType
. - Calculating Token Days Destroyed.
- Transferring admin rights.
- Ensuring only the staker can withdraw their tokens.
- Verifying that the admin cannot access stakers' tokens.
To run the tests:
move package test
We welcome contributions from the team! Please follow these guidelines:
- Fork the repository and create a new branch for your feature or bug fix.
- Ensure all tests pass before submitting a pull request.
- Follow coding standards: Maintain consistent code formatting and documentation.
- Write tests for new features or bug fixes.
- Submit a Pull Request: Provide a clear description of your changes and any relevant issue numbers.
This project is licensed under the MIT License. See the LICENSE file for details.
For questions or discussions, please open an issue in the repository or contact the project maintainer:
- Your Name
- Email: [email protected]
- Install Move CLI: Follow the instructions on the Move CLI Installation Guide.
- Set Up Aptos Environment: If deploying to Aptos, ensure you have access to an Aptos node or testnet.
- Compile Modules:
move package build
- Run Tests:
move package test
- Publish Modules:
move package publish --url <node_url> --private-key <your_private_key>
- Clean Build Artifacts:
move package clean
- Compilation Errors: Ensure all dependencies are correctly specified in
Move.toml
. - Test Failures: Check the error messages and ensure the tests are updated to reflect any changes in the module.
- Aptos Framework: The module depends on the Aptos Framework for standard functionalities like
Coin
,CoinStore
, andBlock
. Ensure the dependencies are correctly specified in yourMove.toml
:
[dependencies]
AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "main" }
This README file provides all the necessary information for your team to understand, build, test, deploy, and use the Token Days Destroyed Staking Module. It serves as a central reference point for collaboration and project maintenance, incorporating the detailed intended behavior, auditor's comments, and updated module usage instructions.