Skip to main content

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 functions
  • INameService.sol - Identity management and username operations
  • IStaking.sol - Staking and reward distribution functions
  • IEstimator.sol - Economic calculation and estimation functions
  • ITreasury.sol - Treasury management operations
  • ITreasuryHostChainStation.sol - Cross-chain treasury host functions
  • ITreasuryExternalChainStation.sol - Cross-chain treasury external functions

Contracts

Full contract implementations organized by service:

evvm/

  • Evvm.sol - Main EVVM contract implementation
  • EvvmLegacy.sol - Legacy version compatibility
  • lib/ - Supporting libraries

nameService/

  • NameService.sol - Identity service implementation
  • lib/ - Username and metadata utilities

staking/

  • Staking.sol - Staking contract implementation
  • Estimator.sol - Economic estimation contract
  • lib/ - Staking calculation libraries

treasury/

  • Treasury.sol - Single-chain treasury implementation
  • lib/ - Treasury management utilities

treasuryTwoChains/

  • TreasuryHostChainStation.sol - Host chain treasury operations
  • TreasuryExternalChainStation.sol - External chain treasury operations
  • lib/ - Cross-chain communication utilities

Library

Utility libraries for contract development:

  • SignatureRecover.sol - EIP-191 signature verification utilities
  • Erc191TestBuilder.sol - Testing utilities for signature construction
  • AdvancedStrings.sol - String manipulation utilities
  • StakingServiceHooks.sol - Service integration hooks for staking

Usage for Service Developers

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

  1. Interface Integration: Use IEvvm for all EVVM operations
  2. Dual Signature Pattern: Service authorization + payment signatures
  3. Nonce Management: Prevent replay attacks with proper tracking
  4. Staking Integration: Inherit from StakingServiceHooks for service staking
  5. Fisher Incentives: Distribute rewards to encourage transaction processing
  6. 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.