Overview
This guide explains the basics of Paxeer Network development. Paxeer Network is EVM equivalent , meaning it runs the same EVM as Ethereum. Therefore, the differences between Paxeer development and Ethereum development are minimal.
Paxeer Network Chain ID: 229
Paxeer Network Endpoints
To access Paxeer Network, you need an RPC endpoint:
https://public-rpc.paxeer.app/rpc
Parameter Value
Network Name Paxeer Network Chain ID 229 Currency PAX RPC URL https://public-rpc.paxeer.app/rpc Block Explorer https://scan.paxeer.app
Development Workflow
Set Up Your Environment
Choose your development framework:
Hardhat - Most popular, great for testing
Foundry - Fast, Solidity-native testing
Remix - Browser-based, no setup
Configure Network
Add Paxeer Network to your configuration: require ( "@nomicfoundation/hardhat-toolbox" );
require ( 'dotenv' ). config ();
module . exports = {
solidity: "0.8.20" ,
networks: {
paxeer: {
url: "https://public-rpc.paxeer.app/rpc" ,
chainId: 229 ,
accounts: [ process . env . PRIVATE_KEY ],
},
},
};
[ profile . default ]
src = "src"
out = "out"
libs = [ "lib" ]
solc_version = "0.8.20"
[ rpc_endpoints ]
paxeer = "https://public-rpc.paxeer.app/rpc"
[ etherscan ]
paxeer = { key = "${ETHERSCAN_API_KEY}" }
Write Smart Contracts
Write Solidity contracts as you would for Ethereum: // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20 ;
contract MyContract {
uint256 public value;
event ValueChanged ( uint256 newValue );
function setValue ( uint256 _value ) external {
value = _value;
emit ValueChanged (_value);
}
function getValue () external view returns ( uint256 ) {
return value;
}
}
Test Locally
Test with your framework’s local network: # Hardhat
npx hardhat test
# Foundry
forge test
Deploy to Paxeer
Deploy to Paxeer Network: # Hardhat
npx hardhat run scripts/deploy.js --network paxeer
# Foundry
forge create src/MyContract.sol:MyContract \
--rpc-url https://public-rpc.paxeer.app/rpc \
--private-key $PRIVATE_KEY
Verify Contract
Verify your contract on PaxeerScan: # Hardhat
npx hardhat verify --network paxeer DEPLOYED_ADDRESS
# Foundry
forge verify-contract DEPLOYED_ADDRESS \
src/MyContract.sol:MyContract \
--chain-id 229 \
--watch
Development Frameworks
Hardhat
Industry-standard Ethereum development environment with excellent testing framework.
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox
npx hardhat init
Key Features:
Built-in testing with Mocha & Chai
Console.log debugging in Solidity
Mainnet forking
TypeScript support
Plugin ecosystem
Hardhat Documentation Complete Hardhat guides and reference
Foundry
Blazing fast Ethereum toolkit written in Rust with Solidity-based testing.
curl -L https://foundry.paradigm.xyz | bash
foundryup
Key Features:
Extremely fast test execution
Solidity-native tests
Fuzzing support
Gas snapshots
Fork testing
Foundry Documentation The Foundry Book
Remix IDE
Browser-based IDE for quick prototyping and learning.
Access: remix.ethereum.org
Key Features:
No installation required
Visual debugger
Built-in compiler
Direct MetaMask integration
Plugin support
Interacting with Contracts
Using ethers.js
import { ethers } from 'ethers' ;
const provider = new ethers . JsonRpcProvider ( 'https://public-rpc.paxeer.app/rpc' );
const signer = await provider . getSigner ();
// Deploy contract
const MyContract = await ethers . getContractFactory ( 'MyContract' );
const contract = await MyContract . deploy ();
await contract . waitForDeployment ();
console . log ( 'Deployed to:' , await contract . getAddress ());
// Interact with deployed contract
const contractAddress = '0x...' ;
const myContract = new ethers . Contract ( contractAddress , ABI , signer );
// Read
const value = await myContract . getValue ();
// Write
const tx = await myContract . setValue ( 42 );
await tx . wait ();
Using wagmi (React)
import { useReadContract , useWriteContract } from 'wagmi' ;
function MyComponent () {
// Read contract
const { data : value } = useReadContract ({
address: '0x...' ,
abi: contractABI ,
functionName: 'getValue' ,
});
// Write contract
const { writeContract } = useWriteContract ();
function setValue ( newValue : number ) {
writeContract ({
address: '0x...' ,
abi: contractABI ,
functionName: 'setValue' ,
args: [ newValue ],
});
}
return (
< div >
< p > Current value : { value ?. toString ()}</ p >
< button onClick = {() => setValue (42)} > Set Value </ button >
</ div >
);
}
Best Practices
Use Provided EVM for Development
Start with your framework’s local network for fastest iteration: # Hardhat local network
npx hardhat node
# Foundry local network
anvil
Benefits:
Instant mining
Console logging
Easy debugging
Free testing
Test Thoroughly Before Deploying
Follow this testing progression:
Local network - Fast iteration, rich debugging
Testnet - Real network conditions
Mainnet - Production deployment
// Example test
describe ( "MyContract" , function () {
it ( "Should set and get value" , async function () {
const MyContract = await ethers . getContractFactory ( "MyContract" );
const contract = await MyContract . deploy ();
await contract . setValue ( 42 );
expect ( await contract . getValue ()). to . equal ( 42 );
});
});
Always verify contracts on PaxeerScan: Benefits:
Users can read contract source
Direct interaction from explorer
Builds trust
Easier debugging
npx hardhat verify --network paxeer DEPLOYED_ADDRESS [CONSTRUCTOR_ARGS]
Optimize contract gas usage: // Use appropriate data types
uint128 instead of uint256 when possible
// Pack storage variables
struct Packed {
uint128 a; // 16 bytes
uint128 b; // 16 bytes
} // = 1 storage slot
// Use events for data storage
emit DataStored (data); // Cheaper than storage
// Cache storage reads
uint256 cached = storageVar; // Read once
// Use cached value multiple times
Implement comprehensive error handling: try {
const tx = await contract . setValue ( 42 );
const receipt = await tx . wait ();
if ( receipt . status === 0 ) {
console . error ( 'Transaction failed' );
// Handle failure
}
} catch ( error ) {
if ( error . code === 'ACTION_REJECTED' ) {
console . log ( 'User rejected transaction' );
} else if ( error . code === 'INSUFFICIENT_FUNDS' ) {
console . log ( 'Insufficient balance' );
} else {
console . error ( 'Transaction error:' , error );
}
}
Differences from Ethereum
While Paxeer Network is EVM equivalent, there are a few minor differences:
Ethereum: ~12 seconds
Paxeer Network: ~2 seconds
Impact: Faster confirmations, more frequent events
Ethereum: High (varies widely)
Paxeer Network: Very low (99%+ cheaper)
Impact: More economical to run complex operations
All standard EVM opcodes are supported. Paxeer Network is fully EVM equivalent.
Contract Examples
Simple Storage
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20 ;
contract SimpleStorage {
mapping ( address => uint256 ) private values;
event ValueStored ( address indexed user , uint256 value );
function store ( uint256 value ) external {
values[ msg.sender ] = value;
emit ValueStored ( msg.sender , value);
}
function retrieve () external view returns ( uint256 ) {
return values[ msg.sender ];
}
}
ERC-20 Token
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20 ;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol" ;
import "@openzeppelin/contracts/access/Ownable.sol" ;
contract MyToken is ERC20 , Ownable {
constructor () ERC20 ("MyToken", "MTK") Ownable (msg.sender) {
_mint ( msg.sender , 1000000 * 10 ** decimals ());
}
function mint ( address to , uint256 amount ) external onlyOwner {
_mint (to, amount);
}
}
NFT Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20 ;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol" ;
import "@openzeppelin/contracts/access/Ownable.sol" ;
contract MyNFT is ERC721 , Ownable {
uint256 private _tokenIdCounter;
constructor () ERC721 ("MyNFT", "MNFT") Ownable (msg.sender) {}
function mint ( address to ) external onlyOwner {
uint256 tokenId = _tokenIdCounter ++ ;
_safeMint (to, tokenId);
}
}
Frontend Integration
Next.js + wagmi Template
'use client'
import { useAccount , useConnect , useReadContract } from 'wagmi'
export default function Home () {
const { address , isConnected } = useAccount ()
const { connect , connectors } = useConnect ()
const { data : value } = useReadContract ({
address: '0xYourContractAddress' ,
abi: contractABI ,
functionName: 'getValue' ,
})
if ( ! isConnected ) {
return (
< div >
{ connectors . map (( connector ) => (
< button
key = {connector. id }
onClick = {() => connect ({ connector })}
>
Connect { connector . name }
</ button >
))}
</ div >
)
}
return (
< div >
< p > Connected : { address }</ p >
< p > Contract Value : { value ?. toString ()}</ p >
</ div >
)
}
Testing Strategies
Unit Tests
Integration Tests
Mainnet Fork
Test individual contract functions: const { expect } = require ( "chai" );
const { ethers } = require ( "hardhat" );
describe ( "MyContract" , function () {
let contract ;
let owner ;
beforeEach ( async function () {
[ owner ] = await ethers . getSigners ();
const MyContract = await ethers . getContractFactory ( "MyContract" );
contract = await MyContract . deploy ();
});
it ( "Should set and get value" , async function () {
await contract . setValue ( 42 );
expect ( await contract . getValue ()). to . equal ( 42 );
});
it ( "Should emit event" , async function () {
await expect ( contract . setValue ( 42 ))
. to . emit ( contract , "ValueChanged" )
. withArgs ( 42 );
});
});
Test interactions between contracts: describe ( "Token Integration" , function () {
let token , vault ;
beforeEach ( async function () {
// Deploy contracts
const Token = await ethers . getContractFactory ( "MyToken" );
token = await Token . deploy ();
const Vault = await ethers . getContractFactory ( "Vault" );
vault = await Vault . deploy ( await token . getAddress ());
});
it ( "Should deposit tokens to vault" , async function () {
const amount = ethers . parseEther ( "100" );
// Approve
await token . approve ( await vault . getAddress (), amount );
// Deposit
await vault . deposit ( amount );
// Verify
expect ( await vault . balances ( owner . address )). to . equal ( amount );
});
});
Test against real deployed contracts: networks : {
hardhat : {
forking : {
url : "https://public-rpc.paxeer.app/rpc" ,
blockNumber : 1000000 , // Optional: pin to specific block
},
},
}
// Test against real contracts
describe ( "Mainnet Fork Tests" , function () {
it ( "Should interact with deployed PaxDex" , async function () {
const vault = await ethers . getContractAt (
"PaxDexVault" ,
"0x49B0f9a0554da1A7243A9C8ac5B45245A66D90ff"
);
// Test interaction
const price = await vault . getPrice ( tokenAddress );
console . log ( "Token price:" , price );
});
});
Security Considerations
Common Vulnerabilities
Use checks-effects-interactions pattern: function withdraw ( uint256 amount ) external {
// Checks
require (balances[ msg.sender ] >= amount, "Insufficient balance" );
// Effects
balances[ msg.sender ] -= amount;
// Interactions
( bool success, ) = msg.sender .call{value : amount}( "" );
require (success, "Transfer failed" );
}
Or use OpenZeppelin’s ReentrancyGuard: import "@openzeppelin/contracts/security/ReentrancyGuard.sol" ;
contract Safe is ReentrancyGuard {
function withdraw () external nonReentrant {
// Protected from reentrancy
}
}
Solidity 0.8+ has built-in overflow protection: // Automatically safe in 0.8+
uint256 a = 100 ;
uint256 b = 200 ;
uint256 c = a + b; // Can't overflow
For unchecked operations: unchecked {
// Only use when you're certain it's safe
counter ++ ;
}
Properly restrict sensitive functions: import "@openzeppelin/contracts/access/Ownable.sol" ;
contract MyContract is Ownable {
constructor () Ownable (msg.sender) {}
function adminFunction () external onlyOwner {
// Only owner can call
}
}
Example Projects
Next Steps