Testnet Contracts
The @evvm/testnet-contracts package provides Solidity interfaces and implementations for all EVVM smart contracts documented in this site. This package enables developers to integrate EVVM functionality directly into their smart contracts.
Package Structure
Interfaces
Ready-to-use interfaces for all EVVM contracts:
IEvvm.sol- Core payment and transaction functionsINameService.sol- Identity management and username operationsIStaking.sol- Staking and reward distribution functionsIEstimator.sol- Economic calculation and estimation functionsITreasury.sol- Treasury management operationsITreasuryHostChainStation.sol- Cross-chain treasury host functionsITreasuryExternalChainStation.sol- Cross-chain treasury external functions
Contracts
Full contract implementations organized by service:
evvm/
Evvm.sol- Main EVVM contract implementationEvvmLegacy.sol- Legacy version compatibilitylib/- Supporting libraries
nameService/
NameService.sol- Identity service implementationlib/- Username and metadata utilities
staking/
Staking.sol- Staking contract implementationEstimator.sol- Economic estimation contractlib/- Staking calculation libraries
treasury/
Treasury.sol- Single-chain treasury implementationlib/- Treasury management utilities
treasuryTwoChains/
TreasuryHostChainStation.sol- Host chain treasury operationsTreasuryExternalChainStation.sol- External chain treasury operationslib/- Cross-chain communication utilities
Library
Utility libraries for contract development:
SignatureRecover.sol- EIP-191 signature verification utilitiesErc191TestBuilder.sol- Testing utilities for signature constructionAdvancedStrings.sol- String manipulation utilitiesStakingServiceHooks.sol- Service integration hooks for staking
Usage for Service Developers
Recommended Approach: Use Interfaces
For developers creating EVVM services, we strongly recommend using the interfaces rather than full contract implementations:
import "@evvm/testnet-contracts/interfaces/IEvvm.sol";
import "@evvm/testnet-contracts/interfaces/INameService.sol";
contract MyService {
IEvvm public immutable evvm;
INameService public immutable nameService;
constructor(address _evvm, address _nameService) {
evvm = IEvvm(_evvm);
nameService = INameService(_nameService);
}
function makePayment(address to, uint256 amount) external {
// Use EVVM interface for payments
evvm.pay(/* parameters */);
}
}
Benefits of Using Interfaces
- Lighter Dependencies: Only import what you need
- Future Compatibility: Interfaces remain stable across contract upgrades
- Gas Efficiency: No unnecessary code deployment
- Clean Integration: Focus on functionality, not implementation details
Installation
npm install @evvm/testnet-contracts
Generic Service Implementation Pattern
Here's a complete template demonstrating best practices for EVVM service integration:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {IEvvm} from "@evvm/testnet-contracts/interfaces/IEvvm.sol";
import {SignatureRecover} from "@evvm/testnet-contracts/library/SignatureRecover.sol";
import {StakingServiceHooks} from "@evvm/testnet-contracts/library/StakingServiceHooks.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
contract EVVMService is StakingServiceHooks {
// State variables
address evvmAddress;
address serviceOwner;
address constant ETHER_ADDRESS = address(0);
address constant PRINCIPAL_TOKEN_ADDRESS = address(1);
mapping(address => mapping(uint256 => bool)) usedNonces;
constructor(
address _evvmAddress,
address _stakingAddress,
address _serviceOwner
) StakingServiceHooks(_stakingAddress) {
evvmAddress = _evvmAddress;
serviceOwner = _serviceOwner;
}
function executeService(
address clientAddress,
string memory serviceData,
uint256 serviceAmount,
uint256 nonce,
bytes memory signature,
uint256 priorityFee_EVVM,
uint256 nonce_EVVM,
bool priorityFlag_EVVM,
bytes memory signature_EVVM
) external {
// 1. Verify client signature for service authorization
require(
SignatureRecover.signatureVerification(
Strings.toString(IEvvm(evvmAddress).getEvvmID()),
"executeService",
string.concat(
serviceData, ",",
Strings.toString(serviceAmount), ",",
Strings.toString(nonce)
),
signature,
clientAddress
),
"Invalid signature"
);
// 2. Prevent replay attacks
require(!usedNonces[clientAddress][nonce], "Nonce already used");
// 3. Process payment through EVVM
IEvvm(evvmAddress).pay(
clientAddress, // from
address(this), // to_address
"", // to_identity
ETHER_ADDRESS, // token
serviceAmount, // amount
priorityFee_EVVM, // priorityFee
nonce_EVVM, // nonce
priorityFlag_EVVM, // priority
address(this), // executor
signature_EVVM // signature
);
// 4. Distribute rewards to fisher (if staking)
if (IEvvm(evvmAddress).isAddressStaker(address(this))) {
// Priority fee to fisher
IEvvm(evvmAddress).caPay(
msg.sender,
ETHER_ADDRESS,
priorityFee_EVVM
);
// Share rewards with fisher
IEvvm(evvmAddress).caPay(
msg.sender,
PRINCIPAL_TOKEN_ADDRESS,
IEvvm(evvmAddress).getRewardAmount() / 2
);
}
// 5. Your custom service logic here
_performServiceLogic(clientAddress, serviceData, serviceAmount);
usedNonces[clientAddress][nonce] = true;
}
function _performServiceLogic(
address client,
string memory data,
uint256 amount
) internal {
// Implement your service-specific functionality here
}
// Service staking functions using inherited hooks
function stake(uint256 amountToStake) external {
require(msg.sender == serviceOwner, "Unauthorized");
_makeStakeService(amountToStake);
}
function unstake(uint256 amountToUnstake) external {
require(msg.sender == serviceOwner, "Unauthorized");
_makeUnstakeService(amountToUnstake);
}
}
Essential Implementation Patterns
- Interface Integration: Use
IEvvmfor all EVVM operations - Dual Signature Pattern: Service authorization + payment signatures
- Nonce Management: Prevent replay attacks with proper tracking
- Staking Integration: Inherit from
StakingServiceHooksfor service staking - Fisher Incentives: Distribute rewards to encourage transaction processing
- Modular Design: Separate service logic from EVVM integration
Universal Message Format
Service signatures follow the standard EVVM pattern:
"<evvmID>,<functionName>,<param1>,<param2>,...,<paramN>"
Example for a generic service:
"1,executeService,serviceData,1000000000000000000,100"
This template can be adapted for any service type by:
- Changing function names and parameters
- Implementing custom service logic in
_performServiceLogic - Adding service-specific state variables and functions
This package provides everything needed to integrate with the EVVM ecosystem documented throughout this site, offering both flexibility for advanced use cases and simplicity for standard service development.