Skip to main content

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

Network Information

ParameterValue
Network NamePaxeer Network
Chain ID229
CurrencyPAX
RPC URLhttps://public-rpc.paxeer.app/rpc
Block Explorerhttps://scan.paxeer.app

Development Workflow

1

Set Up Your Environment

Choose your development framework:
  • Hardhat - Most popular, great for testing
  • Foundry - Fast, Solidity-native testing
  • Remix - Browser-based, no setup
2

Configure Network

Add Paxeer Network to your configuration:
hardhat.config.js
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],
    },
  },
};
3

Write Smart Contracts

Write Solidity contracts as you would for Ethereum:
contracts/MyContract.sol
// 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;
    }
}
4

Test Locally

Test with your framework’s local network:
# Hardhat
npx hardhat test

# Foundry
forge test
5

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
6

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.
Installation
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.
Installation
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

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
Follow this testing progression:
  1. Local network - Fast iteration, rich debugging
  2. Testnet - Real network conditions
  3. 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

SimpleStorage.sol
// 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

MyToken.sol
// 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

MyNFT.sol
// 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);
    }
}

Development Tools

Frontend Integration

Next.js + wagmi Template

app/page.tsx
'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

Test individual contract functions:
test/MyContract.test.js
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);
  });
});

Security Considerations

Security Checklist:
  • Use latest Solidity version (0.8.20+)
  • Import from OpenZeppelin for standards
  • Implement access control
  • Validate all inputs
  • Use SafeMath (built-in 0.8+)
  • Check for reentrancy vulnerabilities
  • Test edge cases
  • Get professional audit for high-value contracts

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
    }
}

Resources & Tools

Example Projects

Next Steps