# Building Apps on HyperPaxeer Source: https://sidiorresearchlabs.mintlify.app/app-developers/guides/building-apps Learn the basics of building applications on HyperPaxeer ## Overview This guide explains the basics of HyperPaxeer development. HyperPaxeer is [EVM equivalent](https://web.archive.org/web/20231127160757/https://medium.com/ethereum-optimism/introducing-evm-equivalence-5c2021deb306), meaning it runs the same EVM as Ethereum. Therefore, the differences between Paxeer development and Ethereum development are minimal. HyperPaxeer Chain ID: **125** ## HyperPaxeer Endpoints To access HyperPaxeer, you need an RPC endpoint: ``` https://public-rpc.paxeer.app/rpc ``` ### Network Information | Parameter | Value | | -------------- | ---------------------------------------------------------------------- | | Network Name | HyperPaxeer | | Chain ID | 125 | | Currency | HPX | | RPC URL | [https://public-rpc.paxeer.app/rpc](https://public-rpc.paxeer.app/rpc) | | Block Explorer | [https://paxscan.io](https://paxscan.io) | ## Development Workflow Choose your development framework: * [Hardhat](https://hardhat.org/) - Most popular, great for testing * [Foundry](https://getfoundry.sh/) - Fast, Solidity-native testing * [Remix](https://remix.ethereum.org/) - Browser-based, no setup Add HyperPaxeer to your configuration: ```javascript hardhat.config.js theme={null} require("@nomicfoundation/hardhat-toolbox"); require('dotenv').config(); module.exports = { solidity: "0.8.20", networks: { paxeer: { url: "https://public-rpc.paxeer.app/rpc", chainId: 125, accounts: [process.env.PRIVATE_KEY], }, }, }; ``` ```toml foundry.toml theme={null} [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 Solidity contracts as you would for Ethereum: ```solidity contracts/MyContract.sol theme={null} // 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 with your framework's local network: ```bash theme={null} # Hardhat npx hardhat test # Foundry forge test ``` Deploy to HyperPaxeer: ```bash theme={null} # 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 your contract on PaxScan: ```bash theme={null} # Hardhat npx hardhat verify --network paxeer DEPLOYED_ADDRESS # Foundry forge verify-contract DEPLOYED_ADDRESS \ src/MyContract.sol:MyContract \ --chain-id 125 \ --watch ``` ## Development Frameworks ### Hardhat Industry-standard Ethereum development environment with excellent testing framework. ```bash Installation theme={null} 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 Complete Hardhat guides and reference *** ### Foundry Blazing fast Ethereum toolkit written in Rust with Solidity-based testing. ```bash Installation theme={null} curl -L https://foundry.paradigm.xyz | bash foundryup ``` **Key Features:** * Extremely fast test execution * Solidity-native tests * Fuzzing support * Gas snapshots * Fork testing The Foundry Book *** ### Remix IDE Browser-based IDE for quick prototyping and learning. **Access:** [remix.ethereum.org](https://remix.ethereum.org) **Key Features:** * No installation required * Visual debugger * Built-in compiler * Direct MetaMask integration * Plugin support ## Interacting with Contracts ### Using ethers.js ```javascript theme={null} 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) ```typescript theme={null} 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 (

Current value: {value?.toString()}

); } ``` ## Best Practices Start with your framework's local network for fastest iteration: ```bash theme={null} # 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. **Private fork or staging stack** - Realistic integration conditions 3. **Mainnet** - Production deployment ```javascript theme={null} // 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 PaxScan: Benefits: * Users can read contract source * Direct interaction from explorer * Builds trust * Easier debugging ```bash theme={null} npx hardhat verify --network paxeer DEPLOYED_ADDRESS [CONSTRUCTOR_ARGS] ``` Optimize contract gas usage: ```solidity theme={null} // 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: ```javascript theme={null} 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 HyperPaxeer is EVM equivalent, there are a few minor differences: * **Ethereum:** \~12 seconds * **HyperPaxeer:** 277 ms average Impact: Faster confirmations, more frequent events * **Ethereum:** High (varies widely) * **HyperPaxeer:** Very low (99%+ cheaper) Impact: More economical to run complex operations All standard EVM opcodes are supported. HyperPaxeer is fully EVM equivalent. ## Contract Examples ### Simple Storage ```solidity SimpleStorage.sol theme={null} // 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 ```solidity MyToken.sol theme={null} // 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 ```solidity MyNFT.sol theme={null} // 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 Most popular Ethereum development framework Fast, modern Ethereum toolkit Browser-based Solidity IDE Secure contract libraries ## Frontend Integration ### Next.js + wagmi Template ```typescript app/page.tsx theme={null} '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 (
{connectors.map((connector) => ( ))}
) } return (

Connected: {address}

Contract Value: {value?.toString()}

) } ``` ## Testing Strategies Test individual contract functions: ```javascript test/MyContract.test.js theme={null} 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: ```javascript theme={null} 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: ```javascript hardhat.config.js theme={null} networks: { hardhat: { forking: { url: "https://public-rpc.paxeer.app/rpc", blockNumber: 1000000, // Optional: pin to specific block }, }, } ``` ```javascript theme={null} // 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 **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: ```solidity theme={null} 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: ```solidity theme={null} 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: ```solidity theme={null} // Automatically safe in 0.8+ uint256 a = 100; uint256 b = 200; uint256 c = a + b; // Can't overflow ``` For unchecked operations: ```solidity theme={null} unchecked { // Only use when you're certain it's safe counter++; } ``` Properly restrict sensitive functions: ```solidity theme={null} import "@openzeppelin/contracts/access/Ownable.sol"; contract MyContract is Ownable { constructor() Ownable(msg.sender) {} function adminFunction() external onlyOwner { // Only owner can call } } ``` ## Resources & Tools Verify contracts and track transactions Get test HPX tokens Monitor current gas prices ## Example Projects Complete dApp starter template ERC-20 token implementation ERC-721 NFT implementation DeFi protocol integration ## Next Steps Learn testing best practices Master transaction handling View complete code examples Explore development tools # Testing Apps Source: https://sidiorresearchlabs.mintlify.app/app-developers/guides/testing-apps Learn best practices for testing applications on HyperPaxeer ## Overview Testing applications on HyperPaxeer follows the same principles as Ethereum development. This guide covers best practices specific to building reliable applications on HyperPaxeer. For most tests, you don't need Paxeer-specific features. Use your development stack's built-in testing tools for faster iteration. ## Testing Strategy Test individual functions with framework's local network **Tools:** Hardhat Network, Anvil (Foundry), Ganache **Speed:** ⚑ Fastest **When:** 90% of your tests Test interactions with deployed contracts **Tools:** Hardhat forking, Foundry forking **Speed:** ⚑ Fast **When:** Testing with existing protocols Test on live network with real conditions **Network:** Paxeer Testnet (if available) **Speed:** 🐌 Slower **When:** Final validation before mainnet Deploy to production **Network:** HyperPaxeer (Chain ID: 125) **When:** After thorough testing ## Unit Testing ### Hardhat Example ```javascript test/MyContract.test.js theme={null} const { expect } = require("chai"); const { ethers } = require("hardhat"); describe("MyContract", function () { let contract; let owner; let addr1; let addr2; beforeEach(async function () { [owner, addr1, addr2] = await ethers.getSigners(); const MyContract = await ethers.getContractFactory("MyContract"); contract = await MyContract.deploy(); await contract.waitForDeployment(); }); describe("Deployment", function () { it("Should set the right owner", async function () { expect(await contract.owner()).to.equal(owner.address); }); it("Should start with zero value", async function () { expect(await contract.getValue()).to.equal(0); }); }); describe("Transactions", function () { it("Should update value", async function () { await contract.setValue(42); expect(await contract.getValue()).to.equal(42); }); it("Should emit ValueChanged event", async function () { await expect(contract.setValue(42)) .to.emit(contract, "ValueChanged") .withArgs(42); }); it("Should revert when unauthorized", async function () { await expect( contract.connect(addr1).adminFunction() ).to.be.revertedWith("Not authorized"); }); }); describe("Edge Cases", function () { it("Should handle zero value", async function () { await contract.setValue(0); expect(await contract.getValue()).to.equal(0); }); it("Should handle max uint256", async function () { const maxUint = ethers.MaxUint256; await contract.setValue(maxUint); expect(await contract.getValue()).to.equal(maxUint); }); }); }); ``` ### Foundry Example ```solidity test/MyContract.t.sol theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "forge-std/Test.sol"; import "../src/MyContract.sol"; contract MyContractTest is Test { MyContract public myContract; address owner = address(1); address user = address(2); function setUp() public { vm.prank(owner); myContract = new MyContract(); } function testSetValue() public { myContract.setValue(42); assertEq(myContract.getValue(), 42); } function testEventEmission() public { vm.expectEmit(true, true, true, true); emit ValueChanged(42); myContract.setValue(42); } function testUnauthorized() public { vm.prank(user); vm.expectRevert("Not authorized"); myContract.adminFunction(); } function testFuzz_setValue(uint256 value) public { myContract.setValue(value); assertEq(myContract.getValue(), value); } } ``` ## Integration Testing ### Testing with Mainnet Fork Fork HyperPaxeer mainnet to test against real deployed contracts: ```javascript hardhat.config.js theme={null} module.exports = { networks: { hardhat: { forking: { url: "https://public-rpc.paxeer.app/rpc", blockNumber: 1000000, // Optional: pin to block }, }, }, }; ``` ```javascript test/Integration.test.js theme={null} describe("PaxDex Integration", function () { it("Should swap tokens", async function () { const vault = await ethers.getContractAt( "PaxDexVault", "0x49B0f9a0554da1A7243A9C8ac5B45245A66D90ff" ); // Test with real contract const price = await vault.getPrice(wbtcAddress); expect(price).to.be.gt(0); }); }); ``` ```bash theme={null} # Run tests with fork forge test --fork-url https://public-rpc.paxeer.app/rpc ``` ```solidity test/Integration.t.sol theme={null} contract IntegrationTest is Test { function testPaxDexSwap() public { // Fork mainnet vm.createSelectFork("https://public-rpc.paxeer.app/rpc"); // Interact with real contracts PaxDexVault vault = PaxDexVault( 0x49B0f9a0554da1A7243A9C8ac5B45245A66D90ff ); uint256 price = vault.getPrice(wbtcAddress); assertGt(price, 0); } } ``` ## Gas Testing ### Measure and Optimize Gas Usage ```javascript test/Gas.test.js theme={null} describe("Gas Optimization", function () { it("Should track gas usage", async function () { const tx = await contract.setValue(42); const receipt = await tx.wait(); console.log("Gas used:", receipt.gasUsed.toString()); // Assert gas usage is within expected range expect(receipt.gasUsed).to.be.lt(50000); }); it("Should compare optimized vs unoptimized", async function () { // Test optimized function const tx1 = await contract.optimizedFunction(); const receipt1 = await tx1.wait(); // Test unoptimized function const tx2 = await contract.unoptimizedFunction(); const receipt2 = await tx2.wait(); console.log("Optimized gas:", receipt1.gasUsed.toString()); console.log("Unoptimized gas:", receipt2.gasUsed.toString()); expect(receipt1.gasUsed).to.be.lt(receipt2.gasUsed); }); }); ``` ### Foundry Gas Snapshots ```bash theme={null} # Create gas snapshot forge snapshot # Compare with previous forge snapshot --diff ``` ```solidity theme={null} contract GasTest is Test { function testGas_transfer() public { token.transfer(user, 100 ether); } function testGas_batchTransfer() public { address[] memory recipients = new address[](10); // ... test batch operation } } ``` ## Testing Best Practices Aim for high test coverage: ```bash theme={null} # Hardhat coverage npx hardhat coverage # Foundry coverage forge coverage ``` **Target:** * Statements: > 90% * Branches: > 80% * Functions: > 90% * Lines: > 90% Test boundary conditions: ```javascript theme={null} describe("Edge Cases", function () { it("Should handle zero", async function () { await contract.setValue(0); }); it("Should handle max uint256", async function () { await contract.setValue(ethers.MaxUint256); }); it("Should handle empty arrays", async function () { await contract.processBatch([]); }); it("Should handle duplicate values", async function () { await contract.addItem(1); await expect(contract.addItem(1)).to.be.reverted; }); }); ``` Foundry's fuzzing finds edge cases automatically: ```solidity theme={null} // Foundry will test with random values function testFuzz_transfer(uint256 amount) public { vm.assume(amount <= token.balanceOf(address(this))); token.transfer(user, amount); assertEq(token.balanceOf(user), amount); } function testFuzz_division(uint256 a, uint256 b) public { vm.assume(b != 0); uint256 result = a / b; assertLe(result, a); } ``` Verify events are emitted correctly: ```javascript theme={null} it("Should emit Transfer event", async function () { await expect(token.transfer(addr1.address, 100)) .to.emit(token, "Transfer") .withArgs(owner.address, addr1.address, 100); }); ``` Test time-dependent functionality: ```javascript theme={null} it("Should unlock after time period", async function () { await contract.lock(); // Fast forward time await ethers.provider.send("evm_increaseTime", [86400]); // 1 day await ethers.provider.send("evm_mine"); await contract.unlock(); }); ``` Foundry: ```solidity theme={null} function testTimeLock() public { contract.lock(); // Warp time forward vm.warp(block.timestamp + 1 days); contract.unlock(); } ``` ## Testing Multi-Contract Interactions ```javascript test/MultiContract.test.js theme={null} describe("Token Vault Integration", function () { let token, vault; let owner, user; beforeEach(async function () { [owner, user] = await ethers.getSigners(); // Deploy token const Token = await ethers.getContractFactory("MyToken"); token = await Token.deploy(); // Deploy vault const Vault = await ethers.getContractFactory("Vault"); vault = await Vault.deploy(await token.getAddress()); // Setup: give user some tokens await token.transfer(user.address, ethers.parseEther("1000")); }); it("Should deposit and withdraw", async function () { const amount = ethers.parseEther("100"); // User approves vault await token.connect(user).approve(await vault.getAddress(), amount); // User deposits await vault.connect(user).deposit(amount); expect(await vault.balances(user.address)).to.equal(amount); expect(await token.balanceOf(user.address)).to.equal( ethers.parseEther("900") ); // User withdraws await vault.connect(user).withdraw(amount); expect(await vault.balances(user.address)).to.equal(0); expect(await token.balanceOf(user.address)).to.equal( ethers.parseEther("1000") ); }); }); ``` ## Continuous Integration ### GitHub Actions Example ```yaml .github/workflows/test.yml theme={null} name: Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 - name: Run tests run: forge test -vvv - name: Check coverage run: forge coverage ``` ## Mock Contracts for Testing ```solidity test/mocks/MockERC20.sol theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MockERC20 is ERC20 { constructor() ERC20("Mock Token", "MOCK") { _mint(msg.sender, 1000000 * 10 ** decimals()); } function mint(address to, uint256 amount) external { _mint(to, amount); } } ``` ## Testing Checklist Before deploying to HyperPaxeer mainnet: * [ ] All unit tests passing * [ ] Integration tests passing * [ ] Gas costs optimized * [ ] Test coverage > 90% * [ ] Edge cases tested * [ ] Events tested * [ ] Access control tested * [ ] Reentrancy protection verified * [ ] Integer overflow scenarios tested * [ ] Failed transaction scenarios handled * [ ] Tested with mainnet fork * [ ] Security review completed * [ ] Documentation updated ## Testing Tools & Resources Hardhat testing guide Foundry testing guide Ethereum smart contract testing library Ethereum-specific assertions ## Advanced Testing Patterns ### Snapshot Testing ```javascript theme={null} describe("State Snapshots", function () { let snapshotId; beforeEach(async function () { snapshotId = await ethers.provider.send("evm_snapshot"); }); afterEach(async function () { await ethers.provider.send("evm_revert", [snapshotId]); }); it("Should test with clean state", async function () { // Each test starts with fresh state await contract.setValue(42); expect(await contract.getValue()).to.equal(42); }); }); ``` ### Testing Reverts ```javascript theme={null} describe("Revert Scenarios", function () { it("Should revert with message", async function () { await expect( contract.connect(user).adminOnly() ).to.be.revertedWith("Only admin"); }); it("Should revert with custom error", async function () { await expect( contract.invalidOperation() ).to.be.revertedWithCustomError(contract, "InvalidOperation"); }); it("Should revert with panic code", async function () { await expect( contract.divideByZero() ).to.be.revertedWithPanic(0x12); // Division by zero }); }); ``` ### Testing Gas Usage ```javascript theme={null} describe("Gas Optimization", function () { it("Should use less gas than limit", async function () { const tx = await contract.optimizedFunction(); const receipt = await tx.wait(); console.log("Gas used:", receipt.gasUsed.toString()); expect(receipt.gasUsed).to.be.lt(100000); }); it("Should compare gas between implementations", async function () { const tx1 = await contract.methodA(); const receipt1 = await tx1.wait(); const tx2 = await contract.methodB(); const receipt2 = await tx2.wait(); console.log("Method A gas:", receipt1.gasUsed.toString()); console.log("Method B gas:", receipt2.gasUsed.toString()); }); }); ``` ## Load Testing Test your contract under load: ```javascript test/Load.test.js theme={null} describe("Load Testing", function () { it("Should handle batch operations", async function () { const numOperations = 100; const promises = []; for (let i = 0; i < numOperations; i++) { promises.push(contract.setValue(i)); } await Promise.all(promises); // Verify all operations succeeded expect(await contract.getValue()).to.equal(numOperations - 1); }); it("Should handle large arrays", async function () { const largeArray = Array(1000).fill(0).map((_, i) => i); await contract.processBatch(largeArray); }); }); ``` ## Security Testing ```solidity test/Reentrancy.t.sol theme={null} contract ReentrancyTest is Test { Vulnerable vulnerable; Attacker attacker; function setUp() public { vulnerable = new Vulnerable(); attacker = new Attacker(address(vulnerable)); } function testReentrancyAttack() public { vm.deal(address(vulnerable), 10 ether); vm.deal(address(attacker), 1 ether); vm.expectRevert("ReentrancyGuard: reentrant call"); attacker.attack(); } } ``` ```javascript theme={null} describe("Access Control", function () { it("Owner can perform admin actions", async function () { await expect(contract.connect(owner).adminAction()) .to.not.be.reverted; }); it("Non-owner cannot perform admin actions", async function () { await expect(contract.connect(user).adminAction()) .to.be.revertedWith("Ownable: caller is not the owner"); }); it("Should transfer ownership", async function () { await contract.transferOwnership(user.address); expect(await contract.owner()).to.equal(user.address); }); }); ``` ```solidity theme={null} function testOverflow() public { uint256 max = type(uint256).max; // Should revert in 0.8+ vm.expectRevert(); uint256 overflow = max + 1; } ``` ## CI/CD Integration ### Automated Testing Pipeline ```yaml .github/workflows/ci.yml theme={null} name: CI on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: submodules: recursive - name: Install Node.js uses: actions/setup-node@v3 with: node-version: '18' - name: Install dependencies run: npm ci - name: Run tests run: npx hardhat test - name: Check coverage run: npx hardhat coverage - name: Upload coverage uses: codecov/codecov-action@v3 ``` ## Debugging Tests ### Enable Verbose Logging ```bash theme={null} # Hardhat npx hardhat test --verbose # Foundry forge test -vvvv ``` ### Use Console.log in Solidity ```solidity theme={null} import "hardhat/console.sol"; contract Debug { function testFunction(uint256 x) external { console.log("Input value:", x); uint256 result = x * 2; console.log("Result:", result); } } ``` ### Hardhat Debugging ```javascript theme={null} const { ethers } = require("hardhat"); it("Should debug transaction", async function () { const tx = await contract.setValue(42); const receipt = await tx.wait(); console.log("Transaction hash:", receipt.hash); console.log("Block number:", receipt.blockNumber); console.log("Gas used:", receipt.gasUsed.toString()); console.log("Logs:", receipt.logs); }); ``` ## Resources Development guide Code examples Hardhat test guide Foundry test guide ## Next Steps Deploy to HyperPaxeer Understand transactions Security best practices # Estimating Transaction Costs Source: https://sidiorresearchlabs.mintlify.app/app-developers/guides/transactions/estimates Learn how to properly estimate the total cost of a transaction on HyperPaxeer Estimating transaction costs on HyperPaxeer is exactly the same as on Ethereum. You can use the same tools and methods you're already familiar with. ## Overview It's important to properly estimate the cost of a transaction on HyperPaxeer before submitting it. This guide shows you how to estimate the execution gas fee for your transactions. ## Execution Gas Fee A transaction's execution gas fee is equal to the amount of gas used multiplied by the gas price attached to the transaction. ``` executionGasFee = gasUsed Γ— (baseFee + priorityFee) ``` ## Estimation Steps Use `eth_estimateGas` to estimate how much gas your transaction will consume: ```javascript ethers.js theme={null} import { ethers } from 'ethers'; const provider = new ethers.JsonRpcProvider('https://public-rpc.paxeer.app/rpc'); async function estimateGas(tx) { const gasEstimate = await provider.estimateGas(tx); console.log('Estimated gas:', gasEstimate.toString()); return gasEstimate; } // Example: ETH transfer const tx = { to: '0x...', value: ethers.parseEther('1.0'), }; const gas = await estimateGas(tx); ``` ```typescript viem theme={null} import { createPublicClient, http, parseEther } from 'viem'; import { paxeer } from './chains'; const client = createPublicClient({ chain: paxeer, transport: http(), }); async function estimateGas(tx) { const gasEstimate = await client.estimateGas(tx); console.log('Estimated gas:', gasEstimate); return gasEstimate; } // Example: ETH transfer const gas = await estimateGas({ to: '0x...', value: parseEther('1'), }); ``` ```python web3.py theme={null} from web3 import Web3 w3 = Web3(Web3.HTTPProvider('https://public-rpc.paxeer.app/rpc')) # Estimate gas tx = { 'to': '0x...', 'value': w3.to_wei(1, 'ether'), } gas_estimate = w3.eth.estimate_gas(tx) print(f'Estimated gas: {gas_estimate}') ``` HyperPaxeer is EVM equivalent, so gas estimates will match Ethereum exactly. A transaction that uses 100,000 gas on Ethereum will use 100,000 gas on HyperPaxeer. Retrieve current base fee and recommended priority fee: ```javascript ethers.js theme={null} async function getFeeData() { const feeData = await provider.getFeeData(); return { maxFeePerGas: feeData.maxFeePerGas, maxPriorityFeePerGas: feeData.maxPriorityFeePerGas, gasPrice: feeData.gasPrice, }; } const fees = await getFeeData(); console.log('Max fee per gas:', ethers.formatUnits(fees.maxFeePerGas, 'gwei'), 'gwei'); console.log('Priority fee:', ethers.formatUnits(fees.maxPriorityFeePerGas, 'gwei'), 'gwei'); ``` ```typescript viem theme={null} async function getFeeData() { const [gasPrice, maxPriorityFee] = await Promise.all([ client.getGasPrice(), client.estimateMaxPriorityFeePerGas(), ]); return { gasPrice, maxPriorityFee, }; } const fees = await getFeeData(); console.log('Gas price:', fees.gasPrice); console.log('Max priority fee:', fees.maxPriorityFee); ``` ```python web3.py theme={null} # Get fee data gas_price = w3.eth.gas_price max_priority_fee = w3.eth.max_priority_fee print(f'Gas price: {w3.from_wei(gas_price, "gwei")} gwei') print(f'Max priority fee: {w3.from_wei(max_priority_fee, "gwei")} gwei') ``` Multiply gas estimate by gas price: ```javascript theme={null} async function estimateTotalCost(tx) { // Get gas estimate const gasEstimate = await provider.estimateGas(tx); // Get fee data const feeData = await provider.getFeeData(); // Calculate cost with max fee const maxCost = gasEstimate * feeData.maxFeePerGas; // Calculate likely cost with current base fee const likelyCost = gasEstimate * (feeData.maxFeePerGas - feeData.maxPriorityFeePerGas); return { gasEstimate: gasEstimate.toString(), maxFeePerGas: ethers.formatUnits(feeData.maxFeePerGas, 'gwei'), maxCostHPX: ethers.formatEther(maxCost), likelyCostHPX: ethers.formatEther(likelyCost), }; } const estimate = await estimateTotalCost(tx); console.log('Cost estimate:', estimate); ``` ## Complete Example Here's a complete example of estimating costs for a token transfer: ```typescript CompleteEstimate.ts theme={null} import { ethers } from 'ethers'; const provider = new ethers.JsonRpcProvider('https://public-rpc.paxeer.app/rpc'); const ERC20_ABI = [ 'function transfer(address to, uint256 amount) returns (bool)', ]; async function estimateTokenTransfer( tokenAddress: string, to: string, amount: string ) { try { // Create contract instance const token = new ethers.Contract(tokenAddress, ERC20_ABI, provider); // Estimate gas for the transfer const gasEstimate = await token.transfer.estimateGas(to, amount); // Get current fee data const feeData = await provider.getFeeData(); // Add 20% buffer to gas estimate const gasLimit = gasEstimate * 120n / 100n; // Calculate max cost const maxCost = gasLimit * feeData.maxFeePerGas; // Calculate likely cost (using current base fee) const currentBaseFee = feeData.maxFeePerGas - feeData.maxPriorityFeePerGas; const priorityFee = feeData.maxPriorityFeePerGas; const likelyCost = gasLimit * (currentBaseFee + priorityFee); return { gasEstimate: gasEstimate.toString(), gasLimit: gasLimit.toString(), baseFee: ethers.formatUnits(currentBaseFee, 'gwei') + ' gwei', priorityFee: ethers.formatUnits(priorityFee, 'gwei') + ' gwei', maxFeePerGas: ethers.formatUnits(feeData.maxFeePerGas, 'gwei') + ' gwei', maxCostHPX: ethers.formatEther(maxCost), likelyCostHPX: ethers.formatEther(likelyCost), }; } catch (error) { console.error('Estimation failed:', error); throw error; } } // Usage const estimate = await estimateTokenTransfer( '0xTokenAddress', '0xRecipient', ethers.parseUnits('100', 18).toString() ); console.log('Transfer Cost Estimate:', estimate); ``` ## React Hook for Cost Estimation ```typescript useEstimateCost.ts theme={null} import { useState, useEffect } from 'react'; import { usePublicClient } from 'wagmi'; import { formatEther } from 'viem'; export function useEstimateCost(tx: any) { const [estimate, setEstimate] = useState(null); const [loading, setLoading] = useState(true); const client = usePublicClient(); useEffect(() => { if (!tx || !client) return; async function estimateCost() { try { const [gasEstimate, gasPrice] = await Promise.all([ client.estimateGas(tx), client.getGasPrice(), ]); const cost = gasEstimate * gasPrice; setEstimate({ gas: gasEstimate.toString(), gasPrice: gasPrice.toString(), costWei: cost.toString(), costHPX: formatEther(cost), }); } catch (error) { console.error('Cost estimation failed:', error); } finally { setLoading(false); } } estimateCost(); }, [tx, client]); return { estimate, loading }; } ``` ## Gas Estimation Best Practices Gas estimates can be slightly inaccurate. Add a 10-20% buffer: ```javascript theme={null} const gasEstimate = await provider.estimateGas(tx); const gasLimit = gasEstimate * 120n / 100n; // 20% buffer ``` `eth_estimateGas` will revert if the transaction would fail: ```javascript theme={null} try { const gasEstimate = await provider.estimateGas(tx); } catch (error) { // Transaction would fail - check error message console.error('Transaction would revert:', error.message); } ``` Gas estimates assume current blockchain state. If state changes before your transaction is mined, actual gas usage may differ: ```javascript theme={null} // Get estimate close to submission time const gasEstimate = await provider.estimateGas(tx); // Send transaction immediately const txResponse = await signer.sendTransaction({ ...tx, gasLimit: gasEstimate * 120n / 100n, }); ``` Test gas estimates under various conditions: * Different account balances * Different contract states * Edge cases and error scenarios ## Checking Historical Fees Analyze historical fee data to predict future costs: ```javascript theme={null} async function analyzeFeeTrends() { // Get fee history for last 100 blocks const feeHistory = await provider.send('eth_feeHistory', [ '0x64', // 100 blocks in hex 'latest', [25, 50, 75] // 25th, 50th, 75th percentile ]); const baseFees = feeHistory.baseFeePerGas.map(fee => ethers.formatUnits(fee, 'gwei') ); console.log('Average base fee:', baseFees.reduce((a, b) => parseFloat(a) + parseFloat(b)) / baseFees.length ); return feeHistory; } ``` ## Tools & Resources Monitor current gas prices Calculate transaction costs ## Next Steps Understand how fees work Set optimal gas parameters View complete code examples Explore all RPC methods # Transaction Fees Source: https://sidiorresearchlabs.mintlify.app/app-developers/guides/transactions/fees Learn how transaction fees work on HyperPaxeer ## Overview HyperPaxeer is designed to be EVM equivalent, which means it reuses the same Ethereum code and behaves as much like Ethereum as possible. Transaction fees on HyperPaxeer follow the standard Ethereum EIP-1559 fee mechanism with significantly lower costs due to Layer 2 optimization. ## Fee Structure Transaction fees on HyperPaxeer consist of a single component: ``` totalFee = gasUsed Γ— (baseFee + priorityFee) ``` Unlike some Layer 2 solutions, HyperPaxeer does not have an L1 data fee component, making fee estimation simpler and more predictable. ## Execution Gas Fee A transaction's execution gas fee on HyperPaxeer is calculated the same way as on Ethereum. This fee is equal to the amount of gas used by the transaction multiplied by the gas price attached to the transaction. ### How It Works HyperPaxeer uses the [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) mechanism to set the base fee for transactions. The total price per unit gas that a transaction pays is the sum of: 1. **Base Fee** - Minimum price per unit of gas 2. **Priority Fee** - Optional tip to incentivize faster inclusion ```javascript theme={null} gasPrice = baseFee + priorityFee totalFee = gasUsed Γ— gasPrice ``` Because HyperPaxeer is EVM equivalent, **the gas used by a transaction on Paxeer is exactly the same as the gas used by the same transaction on Ethereum**. If a transaction costs 100,000 gas on Ethereum, it will cost 100,000 gas on HyperPaxeer. The only difference is that the gas price on Paxeer is much lower. ### Base Fee The [base fee](https://ethereum.org/en/developers/docs/gas/#base-fee) is the minimum price per unit of gas that a transaction must pay to be included in a block. **Key Points:** * Transactions must specify a maximum base fee higher than the block base fee * The actual fee charged is the block base fee (even if you specify higher) * Base fee adjusts automatically based on network demand * Increases when blocks are full, decreases when blocks are empty The HyperPaxeer base fee behaves exactly like the Ethereum base fee, optimized for fast block times. ```solidity Reading Base Fee theme={null} // Get current base fee uint256 baseFee = block.basefee; ``` ### Priority Fee Just like on Ethereum, HyperPaxeer transactions can specify a **priority fee** (also called a tip). This is a price per unit of gas paid on top of the base fee. **Example:** * Block base fee: 1 gwei * Transaction priority fee: 1 gwei * Total price per gas: 2 gwei **The HyperPaxeer sequencer will prioritize transactions with a higher priority fee** and execute them before transactions with a lower priority fee. If transaction speed is important to your application, set a higher priority fee to ensure quick inclusion. The priority fee is optional and can be set to 0, but some wallets may enforce a minimum value (typically 1 gwei). ### Getting Recommended Fees Use the `eth_maxPriorityFeePerGas` RPC method to estimate a priority fee for quick inclusion: ```javascript JavaScript theme={null} // Get recommended priority fee const priorityFee = await provider.send('eth_maxPriorityFeePerGas', []); console.log('Recommended priority fee:', priorityFee); ``` ```python Python theme={null} from web3 import Web3 w3 = Web3(Web3.HTTPProvider('https://public-rpc.paxeer.app/rpc')) # Get recommended priority fee priority_fee = w3.eth.max_priority_fee print(f'Recommended priority fee: {priority_fee}') ``` ```bash cURL theme={null} curl -X POST https://public-rpc.paxeer.app/rpc \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_maxPriorityFeePerGas", "params": [], "id": 1 }' ``` ## Fee Calculation Examples ### Example 1: Simple Transfer ```javascript theme={null} const gasUsed = 21000; // Standard ETH transfer const baseFee = 1000000000; // 1 gwei const priorityFee = 1000000000; // 1 gwei const totalFee = gasUsed * (baseFee + priorityFee); // = 21000 Γ— 2 gwei = 42,000 gwei = 0.000042 HPX ``` ### Example 2: Contract Interaction ```javascript theme={null} const gasUsed = 150000; // Contract call const baseFee = 1000000000; // 1 gwei const priorityFee = 2000000000; // 2 gwei (higher priority) const totalFee = gasUsed * (baseFee + priorityFee); // = 150000 Γ— 3 gwei = 450,000 gwei = 0.00045 HPX ``` ## Estimating Transaction Costs ```javascript theme={null} import { ethers } from 'ethers'; const provider = new ethers.JsonRpcProvider('https://public-rpc.paxeer.app/rpc'); async function estimateTransactionCost(tx) { // Estimate gas const gasEstimate = await provider.estimateGas(tx); // Get fee data const feeData = await provider.getFeeData(); // Calculate total cost const maxFee = feeData.maxFeePerGas; const estimatedCost = gasEstimate * maxFee; console.log('Estimated gas:', gasEstimate.toString()); console.log('Max fee per gas:', ethers.formatUnits(maxFee, 'gwei'), 'gwei'); console.log('Estimated cost:', ethers.formatEther(estimatedCost), 'HPX'); return estimatedCost; } // Usage const tx = { to: '0x...', value: ethers.parseEther('1.0'), }; await estimateTransactionCost(tx); ``` ```typescript theme={null} import { createPublicClient, http, parseEther } from 'viem'; import { paxeer } from './chains'; const client = createPublicClient({ chain: paxeer, transport: http(), }); async function estimateTransactionCost(tx) { // Estimate gas const gasEstimate = await client.estimateGas(tx); // Get fee data const gasPrice = await client.getGasPrice(); // Calculate total cost const estimatedCost = gasEstimate * gasPrice; console.log('Estimated gas:', gasEstimate); console.log('Gas price:', gasPrice); console.log('Estimated cost:', estimatedCost); return estimatedCost; } // Usage await estimateTransactionCost({ to: '0x...', value: parseEther('1'), }); ``` ```typescript theme={null} import { useEstimateGas, useGasPrice } from 'wagmi'; import { parseEther, formatEther } from 'viem'; function TransactionCostEstimator() { const { data: gasEstimate } = useEstimateGas({ to: '0x...', value: parseEther('1'), }); const { data: gasPrice } = useGasPrice(); const estimatedCost = gasEstimate && gasPrice ? gasEstimate * gasPrice : 0n; return (

Estimated Gas: {gasEstimate?.toString()}

Gas Price: {gasPrice?.toString()}

Estimated Cost: {formatEther(estimatedCost)} HPX

); } ```
## Gas Price Monitoring Monitor current gas prices on HyperPaxeer: ```javascript theme={null} import { ethers } from 'ethers'; const provider = new ethers.JsonRpcProvider('https://public-rpc.paxeer.app/rpc'); async function monitorGasPrices() { const feeData = await provider.getFeeData(); console.log({ baseFee: ethers.formatUnits(feeData.maxFeePerGas, 'gwei'), priorityFee: ethers.formatUnits(feeData.maxPriorityFeePerGas, 'gwei'), }); } // Check gas prices every 10 seconds setInterval(monitorGasPrices, 10000); ``` ## Best Practices * Always estimate gas before sending transactions * Add a 10-20% buffer to gas estimates for safety * Don't set gas limits too high (wastes money) or too low (transaction fails) ```javascript theme={null} const gasEstimate = await contract.estimateGas.transfer(to, amount); const gasLimit = gasEstimate * 120n / 100n; // 20% buffer ``` * Check current base fee before submitting time-sensitive transactions * Set max fee per gas higher than current base fee to avoid stuck transactions * Use `eth_feeHistory` to analyze fee trends ```javascript theme={null} const feeHistory = await provider.send('eth_feeHistory', [ '0x10', // 16 blocks 'latest', [] ]); ``` * Set higher priority fees for time-sensitive transactions * Use 0 or low priority fees for non-urgent transactions * Check recommended priority fee with `eth_maxPriorityFeePerGas` * Always check transaction status before assuming success * Implement proper error handling * Consider transaction timeouts ```javascript theme={null} try { const tx = await signer.sendTransaction(txRequest); const receipt = await tx.wait(); if (receipt.status === 0) { throw new Error('Transaction failed'); } } catch (error) { console.error('Transaction error:', error); } ``` ## Fee Vault The Sequencer Fee Vault collects and holds transaction fees paid to the sequencer during block production on HyperPaxeer. **Vault Address:** `0x4200000000000000000000000000000000000011` ### How It Works 1. **Fee Collection**: During transaction processing, the sequencer collects fees from users 2. **Storage**: Collected fees are deposited into the Sequencer Fee Vault contract 3. **Distribution**: Fees are distributed to cover operational costs and network maintenance ## Comparing Costs ### HyperPaxeer vs Ethereum | Operation | Ethereum | HyperPaxeer | Savings | | ------------------------- | ---------- | ------------- | ------- | | ETH Transfer (21,000 gas) | \~\$5-20 | \~\$0.01-0.05 | 99%+ | | Token Swap (150,000 gas) | \~\$30-100 | \~\$0.05-0.20 | 99%+ | | NFT Mint (200,000 gas) | \~\$40-150 | \~\$0.10-0.30 | 99%+ | Actual costs vary based on current gas prices. HyperPaxeer typically offers 99%+ cost savings compared to Ethereum mainnet. ## Advanced Topics ### EIP-1559 Parameters HyperPaxeer uses EIP-1559 with these parameters: | Parameter | Value | Description | | --------------------- | -------------- | ----------------------------------------------- | | Block Gas Limit | 30,000,000 | Maximum gas per block | | Block Time | 277 ms average | Official reported average block production time | | Base Fee Max Change | 12.5% | Maximum base fee change per block | | Elasticity Multiplier | 2 | Block gas target multiplier | ### Gas Price Oracle Query the Gas Price Oracle for current fee data: ```solidity theme={null} // Gas Price Oracle address address constant GAS_PRICE_ORACLE = 0x420000000000000000000000000000000000000F; interface IGasPriceOracle { function gasPrice() external view returns (uint256); function baseFee() external view returns (uint256); } // Usage IGasPriceOracle oracle = IGasPriceOracle(GAS_PRICE_ORACLE); uint256 currentBaseFee = oracle.baseFee(); ``` ## Troubleshooting If your transaction is stuck, it's likely because the max fee per gas is too low: **Solution:** * Set a higher max fee per gas (e.g., 10 gwei) * Or cancel the transaction by sending a new one with the same nonce and higher fee Transaction ran out of gas during execution: **Solution:** * Increase gas limit * Check for infinite loops or excessive computation * Optimize contract code Account doesn't have enough HPX to cover gas costs: **Solution:** * Ensure account has sufficient HPX balance * Remember: required balance = (gas limit Γ— max fee per gas) + value ## Next Steps Learn how to properly estimate transaction costs Set optimal gas parameters for your transactions Track and verify transaction status Fix common transaction issues # Transaction Gas Parameters Source: https://sidiorresearchlabs.mintlify.app/app-developers/guides/transactions/parameters Learn how to set optimal gas parameters for your transactions on HyperPaxeer ## Overview Setting the right gas parameters ensures your transactions are processed efficiently and cost-effectively on HyperPaxeer. ## Gas Parameters EIP-1559 transactions on HyperPaxeer use these gas parameters: Maximum amount of gas you're willing to consume Maximum total gas price you're willing to pay (base + priority) Maximum tip you're willing to pay to the sequencer ## Setting Gas Limit The gas limit is the maximum amount of gas your transaction can consume. ### Best Practices Always estimate gas before setting the limit: ```javascript theme={null} const gasEstimate = await provider.estimateGas(tx); const gasLimit = gasEstimate * 120n / 100n; // Add 20% buffer ``` Add 10-20% buffer to handle minor variations: | Transaction Type | Recommended Buffer | | ----------------- | ------------------ | | Simple transfers | 10% | | Token transfers | 15% | | Complex contracts | 20% | | DeFi interactions | 25% | While unused gas is refunded, setting the limit too high: * Requires more HPX in your wallet upfront * May trigger wallet warnings * Can indicate poorly optimized contracts ### Common Gas Limits | Operation | Typical Gas | With Buffer | | --------------- | ----------- | ----------- | | ETH transfer | 21,000 | 25,000 | | ERC-20 transfer | 65,000 | 78,000 | | ERC-20 approve | 45,000 | 54,000 | | Uniswap swap | 150,000 | 180,000 | | NFT mint | 200,000 | 240,000 | ## Setting Max Fee Per Gas The `maxFeePerGas` is the absolute maximum you're willing to pay per gas unit. ### Recommended Strategy ```javascript theme={null} const feeData = await provider.getFeeData(); const currentBaseFee = feeData.maxFeePerGas - feeData.maxPriorityFeePerGas; ``` ```javascript theme={null} // Base fee can increase up to 12.5% per block // For 5 blocks safety: 1.125^5 β‰ˆ 1.8 const maxBaseFee = currentBaseFee * 2n; // 100% buffer ``` ```javascript theme={null} const priorityFee = feeData.maxPriorityFeePerGas; const maxFeePerGas = maxBaseFee + priorityFee; ``` ### Example Implementation ```javascript theme={null} async function calculateOptimalMaxFee() { const feeData = await provider.getFeeData(); // Current fees const currentBaseFee = feeData.maxFeePerGas - feeData.maxPriorityFeePerGas; const priorityFee = feeData.maxPriorityFeePerGas; // Add 100% buffer to base fee const maxBaseFee = currentBaseFee * 2n; // Calculate max fee per gas const maxFeePerGas = maxBaseFee + priorityFee; return { maxFeePerGas, maxPriorityFeePerGas: priorityFee, }; } // Usage const fees = await calculateOptimalMaxFee(); const tx = await signer.sendTransaction({ to: '0x...', value: ethers.parseEther('1.0'), maxFeePerGas: fees.maxFeePerGas, maxPriorityFeePerGas: fees.maxPriorityFeePerGas, }); ``` ## Setting Priority Fee The priority fee (tip) incentivizes the sequencer to include your transaction faster. ### Priority Levels **When to use:** Non-urgent transactions ```javascript theme={null} const priorityFee = 0n; // or 1 gwei minimum ``` * **Speed:** May take several blocks * **Cost:** Minimal * **Use case:** Batch operations, non-time-sensitive transfers **When to use:** Normal transactions ```javascript theme={null} const priorityFee = await provider.send('eth_maxPriorityFeePerGas', []); ``` * **Speed:** Usually next block * **Cost:** Average * **Use case:** Regular transfers, most dApp interactions **When to use:** Urgent transactions ```javascript theme={null} const recommendedFee = await provider.send('eth_maxPriorityFeePerGas', []); const priorityFee = BigInt(recommendedFee) * 2n; // 2x recommended ``` * **Speed:** Very likely next block * **Cost:** Higher * **Use case:** MEV protection, arbitrage, time-sensitive operations ## Legacy vs EIP-1559 Transactions ### Type 2 Transactions Modern transaction type with better fee market: ```javascript theme={null} const tx = await signer.sendTransaction({ to: '0x...', value: ethers.parseEther('1.0'), maxFeePerGas: ethers.parseUnits('2', 'gwei'), maxPriorityFeePerGas: ethers.parseUnits('1', 'gwei'), }); ``` **Advantages:** * More predictable fees * Better UX (only pay actual base fee) * Automatic refunds for overpayment ### Type 0 Transactions Old-style transactions with single gas price: ```javascript theme={null} const tx = await signer.sendTransaction({ to: '0x...', value: ethers.parseEther('1.0'), gasPrice: ethers.parseUnits('2', 'gwei'), }); ``` **Note:** Still supported but EIP-1559 is preferred ## Complete Transaction Example ```typescript SendOptimizedTransaction.ts theme={null} import { ethers } from 'ethers'; async function sendOptimizedTransaction(to: string, value: bigint) { const provider = new ethers.JsonRpcProvider('https://public-rpc.paxeer.app/rpc'); const signer = await provider.getSigner(); // 1. Estimate gas const tx = { to, value }; const gasEstimate = await provider.estimateGas(tx); const gasLimit = gasEstimate * 120n / 100n; // 20% buffer // 2. Get fee data const feeData = await provider.getFeeData(); // 3. Calculate optimal fees const currentBaseFee = feeData.maxFeePerGas - feeData.maxPriorityFeePerGas; const maxBaseFee = currentBaseFee * 2n; // 100% buffer const priorityFee = feeData.maxPriorityFeePerGas; const maxFeePerGas = maxBaseFee + priorityFee; // 4. Estimate cost const estimatedCost = gasLimit * (currentBaseFee + priorityFee); console.log('Transaction Details:'); console.log('- Gas Limit:', gasLimit.toString()); console.log('- Max Fee:', ethers.formatUnits(maxFeePerGas, 'gwei'), 'gwei'); console.log('- Priority Fee:', ethers.formatUnits(priorityFee, 'gwei'), 'gwei'); console.log('- Estimated Cost:', ethers.formatEther(estimatedCost), 'HPX'); // 5. Send transaction const txResponse = await signer.sendTransaction({ to, value, gasLimit, maxFeePerGas, maxPriorityFeePerGas: priorityFee, }); console.log('Transaction sent:', txResponse.hash); // 6. Wait for confirmation const receipt = await txResponse.wait(); // 7. Calculate actual cost const actualCost = receipt.gasUsed * receipt.gasPrice; console.log('Actual Cost:', ethers.formatEther(actualCost), 'HPX'); return receipt; } ``` ## Network-Specific Considerations ### HyperPaxeer Specifics | Parameter | Value | Notes | | ------------------- | --------------- | --------------------------------- | | Average Base Fee | \~1 gwei | Much lower than Ethereum | | Block Time | 277 ms average | Faster than Ethereum's 12 seconds | | Block Gas Limit | 30M | Same as Ethereum | | Max Base Fee Change | 12.5% per block | EIP-1559 standard | ### Fee Estimation Formula ```javascript theme={null} // Minimum balance needed const minBalance = (gasLimit Γ— maxFeePerGas) + value; // Likely actual cost (optimistic) const likelyCost = (gasLimit Γ— currentBaseFee) + (gasUsed Γ— priorityFee); // Maximum possible cost (pessimistic) const maxCost = gasLimit Γ— maxFeePerGas; ``` ## Error Prevention Common mistakes to avoid: 1. **Setting gasLimit too low** β†’ Transaction fails 2. **Setting maxFeePerGas too low** β†’ Transaction stuck in mempool 3. **Not adding buffer to estimates** β†’ Transaction may fail 4. **Using stale fee data** β†’ Overpaying or stuck transactions ## Next Steps Understand fee components Estimate transaction costs Fix transaction issues View code examples # Transaction Statuses Source: https://sidiorresearchlabs.mintlify.app/app-developers/guides/transactions/statuses Learn about different transaction statuses on HyperPaxeer ## Overview Understanding transaction statuses helps you build reliable applications on HyperPaxeer. This guide explains the lifecycle and finality of transactions. ## Transaction Lifecycle Transaction is in the mempool, waiting to be included in a block. ```javascript theme={null} const tx = await signer.sendTransaction(txData); console.log('Transaction hash:', tx.hash); // Status: Pending ``` Transaction has been included in a block. ```javascript theme={null} const receipt = await tx.wait(1); // Wait for 1 confirmation console.log('Block number:', receipt.blockNumber); // Status: Mined (1 confirmation) ``` Transaction has received multiple block confirmations. ```javascript theme={null} const receipt = await tx.wait(3); // Wait for 3 confirmations // Status: Confirmed (3 confirmations) ``` Transaction is considered final and irreversible. ```javascript theme={null} const receipt = await tx.wait(12); // Wait for 12 confirmations // Status: Finalized ``` ## Checking Transaction Status ### Using Transaction Hash ```javascript ethers.js theme={null} import { ethers } from 'ethers'; const provider = new ethers.JsonRpcProvider('https://public-rpc.paxeer.app/rpc'); async function getTransactionStatus(txHash) { // Get transaction data const tx = await provider.getTransaction(txHash); if (!tx) { return { status: 'not_found' }; } // Get transaction receipt const receipt = await provider.getTransactionReceipt(txHash); if (!receipt) { return { status: 'pending', nonce: tx.nonce, }; } // Get current block number const currentBlock = await provider.getBlockNumber(); const confirmations = currentBlock - receipt.blockNumber + 1; return { status: receipt.status === 1 ? 'success' : 'failed', blockNumber: receipt.blockNumber, confirmations: confirmations, gasUsed: receipt.gasUsed.toString(), effectiveGasPrice: receipt.gasPrice.toString(), }; } // Usage const status = await getTransactionStatus('0x...'); console.log('Transaction status:', status); ``` ```typescript viem theme={null} import { createPublicClient, http } from 'viem'; import { paxeer } from './chains'; const client = createPublicClient({ chain: paxeer, transport: http(), }); async function getTransactionStatus(hash) { // Get transaction const tx = await client.getTransaction({ hash }); if (!tx) { return { status: 'not_found' }; } // Get receipt const receipt = await client.getTransactionReceipt({ hash }); if (!receipt) { return { status: 'pending' }; } // Get confirmations const currentBlock = await client.getBlockNumber(); const confirmations = currentBlock - receipt.blockNumber + 1n; return { status: receipt.status === 'success' ? 'success' : 'failed', blockNumber: receipt.blockNumber, confirmations: confirmations.toString(), gasUsed: receipt.gasUsed.toString(), }; } ``` ```python web3.py theme={null} from web3 import Web3 w3 = Web3(Web3.HTTPProvider('https://public-rpc.paxeer.app/rpc')) def get_transaction_status(tx_hash): # Get transaction try: tx = w3.eth.get_transaction(tx_hash) except: return {'status': 'not_found'} # Try to get receipt try: receipt = w3.eth.get_transaction_receipt(tx_hash) except: return {'status': 'pending', 'nonce': tx['nonce']} # Get confirmations current_block = w3.eth.block_number confirmations = current_block - receipt['blockNumber'] + 1 return { 'status': 'success' if receipt['status'] == 1 else 'failed', 'blockNumber': receipt['blockNumber'], 'confirmations': confirmations, 'gasUsed': receipt['gasUsed'], } # Usage status = get_transaction_status('0x...') print(status) ``` ## Finality Levels HyperPaxeer has different finality levels based on block confirmations: | Level | Confirmations | Time | Use Case | | ------------- | ------------- | -------------- | ----------------------------- | | **Unsafe** | 0 | Immediate | UI updates only | | **Safe** | 1-2 | \~4 seconds | Most dApps | | **Confirmed** | 3-11 | \~6-22 seconds | Important operations | | **Finalized** | 12+ | \~24+ seconds | Critical/irreversible actions | For high-value or critical operations, wait for at least 12 confirmations before considering the transaction finalized. ## Monitoring Transactions ### Real-time Status Updates ```typescript useTransactionStatus.ts theme={null} import { useState, useEffect } from 'react'; import { usePublicClient, useWaitForTransactionReceipt } from 'wagmi'; export function useTransactionStatus(hash?: `0x${string}`) { const [status, setStatus] = useState<'pending' | 'success' | 'failed'>('pending'); const [confirmations, setConfirmations] = useState(0); const { data: receipt, isLoading } = useWaitForTransactionReceipt({ hash, }); const client = usePublicClient(); useEffect(() => { if (!receipt || !client) return; setStatus(receipt.status === 'success' ? 'success' : 'failed'); // Update confirmations periodically const interval = setInterval(async () => { const currentBlock = await client.getBlockNumber(); const confs = currentBlock - receipt.blockNumber + 1n; setConfirmations(Number(confs)); }, 2000); return () => clearInterval(interval); }, [receipt, client]); return { status, confirmations, receipt, isLoading }; } ``` ### Usage in React Component ```typescript theme={null} function TransactionTracker({ txHash }) { const { status, confirmations, receipt } = useTransactionStatus(txHash); return (

Status: {status}

Confirmations: {confirmations}

{status === 'success' && confirmations >= 12 && (

βœ“ Transaction Finalized

)} {status === 'failed' && (

βœ— Transaction Failed

)}
); } ``` ## Transaction Receipt Details ```javascript theme={null} async function getDetailedReceipt(txHash) { const receipt = await provider.getTransactionReceipt(txHash); return { // Status status: receipt.status, // 1 = success, 0 = failed // Block information blockNumber: receipt.blockNumber, blockHash: receipt.blockHash, // Gas usage gasUsed: receipt.gasUsed.toString(), gasPrice: receipt.gasPrice.toString(), effectiveGasPrice: receipt.gasPrice.toString(), // Fee calculation totalFee: (receipt.gasUsed * receipt.gasPrice).toString(), // Addresses from: receipt.from, to: receipt.to, contractAddress: receipt.contractAddress, // If contract creation // Transaction details transactionHash: receipt.hash, transactionIndex: receipt.index, // Logs (events) logs: receipt.logs, }; } ``` ## Best Practices Different use cases need different confirmation levels: ```javascript theme={null} // UI update only - show immediately const receipt = await tx.wait(0); // Standard dApp - wait for 1 confirmation const receipt = await tx.wait(1); // Financial operation - wait for 3+ confirmations const receipt = await tx.wait(3); // Critical operation - wait for finality const receipt = await tx.wait(12); ``` Although rare, block reorganizations can happen: ```javascript theme={null} async function waitForSafeConfirmation(txHash) { let previousBlockHash = null; while (true) { const receipt = await provider.getTransactionReceipt(txHash); if (receipt && receipt.confirmations >= 3) { const block = await provider.getBlock(receipt.blockNumber); if (previousBlockHash && block.hash !== previousBlockHash) { console.warn('Reorg detected! Waiting more...'); previousBlockHash = block.hash; continue; } if (!previousBlockHash) { previousBlockHash = block.hash; } // No reorg detected return receipt; } await new Promise(resolve => setTimeout(resolve, 2000)); } } ``` Don't wait indefinitely: ```javascript theme={null} async function waitWithTimeout(txPromise, timeoutMs = 60000) { return Promise.race([ txPromise, new Promise((_, reject) => setTimeout(() => reject(new Error('Transaction timeout')), timeoutMs) ), ]); } // Usage try { const receipt = await waitWithTimeout(tx.wait()); console.log('Success:', receipt.hash); } catch (error) { if (error.message === 'Transaction timeout') { console.log('Transaction taking too long, check status manually'); } } ``` ## Event Monitoring Watch for transaction events in real-time: ```javascript theme={null} // Listen for pending transactions provider.on('pending', (txHash) => { console.log('New pending transaction:', txHash); }); // Listen for mined blocks provider.on('block', async (blockNumber) => { console.log('New block mined:', blockNumber); const block = await provider.getBlock(blockNumber); console.log('Transactions in block:', block.transactions.length); }); // Clean up listeners provider.removeAllListeners('pending'); provider.removeAllListeners('block'); ``` ## Resources Track transactions on PaxScan Check network health ## Next Steps Understand fee components Fix transaction issues View complete examples # Troubleshooting Transactions Source: https://sidiorresearchlabs.mintlify.app/app-developers/guides/transactions/troubleshooting Learn how to troubleshoot common problems with transactions on HyperPaxeer ## Common Issues This guide helps you diagnose and fix common transaction problems on HyperPaxeer. ## Transaction Stuck in Mempool ### Symptoms * Transaction shows as "pending" for extended period * Transaction doesn't get mined * No confirmation after several minutes ### Cause The max fee per gas is too low compared to the current base fee. ### Solution Send a new transaction with the same nonce but higher fee: ```javascript theme={null} import { ethers } from 'ethers'; async function replaceTransaction(originalTx, newMaxFee) { const signer = await provider.getSigner(); // Get the nonce from the stuck transaction const nonce = await originalTx.nonce; // Send new transaction with same nonce, higher fee const newTx = await signer.sendTransaction({ ...originalTx, nonce: nonce, maxFeePerGas: newMaxFee, // Higher than before maxPriorityFeePerGas: ethers.parseUnits('2', 'gwei'), // Higher priority }); console.log('Replacement tx:', newTx.hash); return await newTx.wait(); } ``` Send a 0 value transaction to yourself with same nonce: ```javascript theme={null} async function cancelTransaction(stuckTxNonce) { const signer = await provider.getSigner(); const address = await signer.getAddress(); // Get current fee data const feeData = await provider.getFeeData(); // Send 0 value to yourself with higher fee const cancelTx = await signer.sendTransaction({ to: address, value: 0, nonce: stuckTxNonce, maxFeePerGas: feeData.maxFeePerGas * 2n, // Much higher maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * 2n, gasLimit: 21000, }); console.log('Cancel tx:', cancelTx.hash); return await cancelTx.wait(); } ``` When replacing or canceling a transaction, you must use the **same nonce** as the original transaction. The replacement must also have a **higher gas price** (typically 10%+ more). *** ## Out of Gas Error ### Symptoms * Transaction reverts with "out of gas" error * Transaction receipt shows `status: 0` ### Cause The gas limit was set too low for the transaction's execution. ### Solution ```javascript theme={null} const gasEstimate = await provider.estimateGas(tx); console.log('Required gas:', gasEstimate.toString()); ``` ```javascript theme={null} const gasLimit = gasEstimate * 150n / 100n; // 50% buffer ``` If gas estimates are extremely high: * Contract may have infinite loops * Contract may be poorly optimized * Transaction may be calling expensive operations *** ## Insufficient Funds ### Symptoms * Error: "insufficient funds for gas \* price + value" * Transaction rejected before sending ### Cause Account doesn't have enough HPX to cover: (gasLimit Γ— maxFeePerGas) + value ### Solution ```javascript theme={null} async function checkSufficientBalance(tx) { const signer = await provider.getSigner(); const address = await signer.getAddress(); // Get current balance const balance = await provider.getBalance(address); // Calculate required balance const gasEstimate = await provider.estimateGas(tx); const feeData = await provider.getFeeData(); const maxCost = gasEstimate * feeData.maxFeePerGas; const totalRequired = maxCost + (tx.value || 0n); console.log('Current balance:', ethers.formatEther(balance), 'HPX'); console.log('Required balance:', ethers.formatEther(totalRequired), 'HPX'); if (balance < totalRequired) { throw new Error(`Insufficient funds. Need ${ethers.formatEther(totalRequired - balance)} more HPX`); } return true; } // Usage await checkSufficientBalance(tx); ``` *** ## Transaction Reverted ### Symptoms * Transaction mined but `status: 0` (failed) * Receipt shows gas used but state didn't change ### Cause Contract execution failed due to: * Failed `require()` or `assert()` statement * Out of gas during execution * External call failure * Invalid operation ### Debugging Steps ```javascript theme={null} const receipt = await provider.getTransactionReceipt(txHash); if (receipt.status === 0) { console.log('Transaction failed!'); console.log('Gas used:', receipt.gasUsed.toString()); console.log('Block:', receipt.blockNumber); } ``` Use `eth_call` to simulate before sending: ```javascript theme={null} try { const result = await provider.call(tx); console.log('Simulation successful:', result); } catch (error) { console.error('Simulation failed:', error.message); // Don't send the transaction } ``` ```javascript theme={null} const receipt = await provider.getTransactionReceipt(txHash); receipt.logs.forEach(log => { console.log('Event emitted:', log); }); ``` View detailed error messages on PaxScan: ``` https://paxscan.io/tx/0x... ``` *** ## Nonce Issues ### Nonce Too Low **Error:** "nonce too low" **Cause:** Transaction uses a nonce that's already been used. **Solution:** ```javascript theme={null} // Get the correct nonce const nonce = await provider.getTransactionCount(address, 'pending'); ``` ### Nonce Too High **Error:** "nonce too high" **Cause:** Transaction uses a nonce higher than expected (gap in nonces). **Solution:** ```javascript theme={null} // Always use the next available nonce const nonce = await provider.getTransactionCount(address, 'latest'); ``` ### Nonce Management for Multiple Transactions ```javascript theme={null} async function sendMultipleTransactions(transactions) { const signer = await provider.getSigner(); let nonce = await provider.getTransactionCount( await signer.getAddress(), 'pending' ); const txPromises = transactions.map(async (tx, index) => { const txResponse = await signer.sendTransaction({ ...tx, nonce: nonce + index, }); return txResponse.wait(); }); return await Promise.all(txPromises); } ``` *** ## Gas Price Too Low ### Symptoms * Transaction not being picked up * Sitting in mempool indefinitely ### Solution Set higher fees: ```javascript theme={null} const feeData = await provider.getFeeData(); // Set max fee to 2x current const maxFeePerGas = feeData.maxFeePerGas * 2n; // Set priority fee for faster inclusion const maxPriorityFeePerGas = ethers.parseUnits('2', 'gwei'); ``` *** ## RPC Error: Transaction Underpriced ### Error Message ``` "transaction underpriced" ``` ### Cause Priority fee is too low for current network conditions. ### Solution ```javascript theme={null} // Get recommended priority fee const recommendedPriority = await provider.send('eth_maxPriorityFeePerGas', []); // Use at least the recommended amount const tx = await signer.sendTransaction({ ...txData, maxPriorityFeePerGas: recommendedPriority, }); ``` *** ## Transaction Takes Too Long ### Normal Confirmation Times | Priority | Expected Time | Block Count | | ------------------ | ------------- | ----------- | | Low (0 gwei) | 10-30 seconds | 5-15 blocks | | Standard | 4-10 seconds | 2-5 blocks | | High (2x priority) | 2-4 seconds | 1-2 blocks | ### If Taking Longer ```javascript theme={null} const tx = await provider.getTransaction(txHash); if (!tx) { console.log('Not yet mined'); } else if (!tx.blockNumber) { console.log('In mempool, waiting for block'); } else { console.log('Mined in block:', tx.blockNumber); } ``` Visit the network status page: ``` https://status.paxeer.app ``` If stuck, replace with higher priority fee (see above) *** ## Contract Call Failures ### Common Revert Reasons **Error:** "ERC20: transfer amount exceeds allowance" **Solution:** ```javascript theme={null} // Approve token spending first const token = new ethers.Contract(tokenAddress, ERC20_ABI, signer); const approveTx = await token.approve(spenderAddress, amount); await approveTx.wait(); // Then perform the transfer const transferTx = await token.transfer(toAddress, amount); ``` **Error:** "ERC20: transfer amount exceeds balance" **Solution:** ```javascript theme={null} // Check balance first const balance = await token.balanceOf(address); if (balance < amount) { throw new Error('Insufficient token balance'); } ``` **Error:** Various errors about invalid inputs **Solution:** * Validate all inputs before sending * Check address formats (valid checksummed addresses) * Ensure amounts are in correct units (wei vs ether) * Verify array lengths and types ## Debugging Tools ### Using Tenderly Simulate and debug transactions: ```javascript theme={null} // Use Tenderly's simulation API const simulation = await fetch('https://api.tenderly.co/api/v1/account/me/project/my-project/simulate', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Access-Key': 'YOUR_KEY', }, body: JSON.stringify({ network_id: '125', from: fromAddress, to: toAddress, input: data, value: value.toString(), }), }); const result = await simulation.json(); console.log('Simulation result:', result); ``` ### Using PaxScan Check transaction details and error messages: 1. Go to [https://paxscan.io](https://paxscan.io) 2. Search for your transaction hash 3. View execution trace and error messages 4. Check event logs for clues ## Prevention Checklist Before sending transactions: * [ ] Estimate gas with `eth_estimateGas` * [ ] Add 10-20% buffer to gas estimate * [ ] Check current base fee is reasonable * [ ] Set appropriate priority fee * [ ] Verify account has sufficient balance * [ ] Simulate transaction with `eth_call` first * [ ] Validate all input parameters * [ ] Handle errors gracefully in code ## Getting Help Ask questions and get help Report bugs and issues Investigate transactions Check network status ## Next Steps Understand fee structure Set optimal parameters View working examples # PaxDex Protocol (Legacy) Source: https://sidiorresearchlabs.mintlify.app/archive/paxdex Archived legacy PaxDex API reference. Use HyperPax DEX for current DEX documentation. ## Overview This page is archived legacy documentation. Use [HyperPax DEX](/sidiora/dex) for the current network-operated DEX. A decentralized exchange protocol for seamless token swaps on Paxeer Network with real-time price feeds and WebSocket support. **0.3%** **12 Tokens** **WebSocket** ## Quick Start ``` https://dex-api.paxeer.app ``` ``` wss://dex-api.paxeer.app:3001 ``` ```bash theme={null} curl https://dex-api.paxeer.app/api/health ``` ## Key Features Get live price updates via REST API or WebSocket for all supported tokens. Only 0.3% swap fee (30 basis points) on all token exchanges. Battle-tested vault and oracle contracts for secure swaps. Simple REST API, WebSocket support, and clear documentation. ## REST API ### Endpoints #### GET /api/health Check API health status and service availability. ```bash cURL theme={null} curl https://dex-api.paxeer.app/api/health ``` ```json Response theme={null} { "status": "ok", "timestamp": 1693234567890 } ``` #### GET /api/prices Get current prices for all supported tokens. ```bash cURL theme={null} curl https://dex-api.paxeer.app/api/prices ``` ```json Response theme={null} { "success": true, "data": { "0x96465d06640aff1a00888d4b9217c9eae708c419": { "address": "0x96465d06640aff1a00888d4b9217c9eae708c419", "symbol": "WBTC", "name": "Wrapped Bitcoin", "decimals": 8, "price": 45230.50, "change24h": 2.45, "timestamp": 1693234567890 } } } ``` #### GET /api/prices/:address Get price data for a specific token by address. ```bash cURL theme={null} curl https://dex-api.paxeer.app/api/prices/0x96465d06640aff1a00888d4b9217c9eae708c419 ``` ```json Response theme={null} { "success": true, "data": { "address": "0x96465d06640aff1a00888d4b9217c9eae708c419", "symbol": "WBTC", "price": 45230.50, "change24h": 2.45, "volume24h": 1234567.89 } } ``` #### GET /api/tokens/swap Get enhanced token data optimized for swap interfaces. ```bash cURL theme={null} curl https://dex-api.paxeer.app/api/tokens/swap ``` ```json Response theme={null} { "success": true, "data": [ { "address": "0x96465d06640aff1a00888d4b9217c9eae708c419", "symbol": "WBTC", "name": "Wrapped Bitcoin", "decimals": 8, "price": 45230.50, "liquidity": 15000000, "volume24h": 5000000 } ] } ``` #### GET /api/prices/:address/history Get historical price data (1h, 24h, 7d, 30d). ```bash cURL theme={null} curl https://dex-api.paxeer.app/api/prices/0x96465d06640aff1a00888d4b9217c9eae708c419/history?period=24h ``` ```json Response theme={null} { "success": true, "data": { "prices": [ { "timestamp": 1693234567890, "price": 45230.50 }, { "timestamp": 1693234467890, "price": 45180.20 } ] } } ``` ### Rate Limits * **100** requests per minute per IP * Responses include cache information * No authentication required ## WebSocket API ### Connection Connect to the WebSocket server for real-time price updates: ```javascript theme={null} const ws = new WebSocket('wss://dex-api.paxeer.app:3001'); ws.onopen = () => { console.log('Connected to PaxDex'); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === 'price_update') { console.log('Price update:', data.data); } }; ws.onerror = (error) => { console.error('WebSocket error:', error); }; ws.onclose = () => { console.log('Disconnected from PaxDex'); }; ``` ### Message Format Price update messages follow this format: ```json theme={null} { "type": "price_update", "data": { "0x96465d06640aff1a00888d4b9217c9eae708c419": { "symbol": "WBTC", "price": 45230.50, "change24h": 2.45, "timestamp": 1693234567890 } } } ``` ### React Hook Example ```typescript usePaxDexPrices.ts theme={null} import { useState, useEffect } from 'react'; export const usePaxDexPrices = () => { const [prices, setPrices] = useState({}); const [isConnected, setIsConnected] = useState(false); useEffect(() => { const ws = new WebSocket('wss://dex-api.paxeer.app:3001'); ws.onopen = () => setIsConnected(true); ws.onmessage = (event) => { const message = JSON.parse(event.data); if (message.type === 'price_update') { setPrices(prev => ({ ...prev, ...message.data })); } }; ws.onclose = () => setIsConnected(false); return () => ws.close(); }, []); return { prices, isConnected }; }; ``` ## Smart Contracts ### Deployed Contracts ``` 0x49B0f9a0554da1A7243A9C8ac5B45245A66D90ff ``` [View on Explorer β†’](https://paxscan.io/address/0x49B0f9a0554da1A7243A9C8ac5B45245A66D90ff) ``` 0x6e5da6d7a89c6B7cB0e5c64fcf326292F76A0352 ``` [View on Explorer β†’](https://paxscan.io/address/0x6e5da6d7a89c6B7cB0e5c64fcf326292F76A0352) ### Swap Function ```solidity theme={null} function swapExactTokensForTokens( address _tokenIn, address _tokenOut, uint256 _amountIn, uint256 _minAmountOut ) external ``` ### Fee Constants ```solidity theme={null} uint256 public constant SWAP_FEE_BPS = 30; // 0.3% uint256 public constant BPS_DENOMINATOR = 10000; // 100% ``` Fee calculation: `30 / 10000 = 0.003 = 0.3%` ### Implementation Example ```javascript theme={null} import { ethers } from 'ethers'; const VAULT_ADDRESS = '0x49B0f9a0554da1A7243A9C8ac5B45245A66D90ff'; const VAULT_ABI = [/* ... */]; async function swap(tokenInAddress, tokenOutAddress, amountIn, minAmountOut) { const signer = await provider.getSigner(); const vault = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, signer); // 1. Approve token spending const tokenIn = new ethers.Contract(tokenInAddress, ERC20_ABI, signer); const approveTx = await tokenIn.approve(VAULT_ADDRESS, amountIn); await approveTx.wait(); // 2. Execute swap const swapTx = await vault.swapExactTokensForTokens( tokenInAddress, tokenOutAddress, amountIn, minAmountOut ); const receipt = await swapTx.wait(); console.log('Swap completed:', receipt.hash); } ``` ## Supported Tokens All tokens are deployed on Paxeer Network (Chain ID: 125) | Token | Name | Address | Decimals | | ------ | ---------------- | -------------------------------------------- | -------- | | WBTC | Wrapped Bitcoin | `0x96465d06640aff1a00888d4b9217c9eae708c419` | 8 | | wstETH | Wrapped stETH | `0xeb2c4ae6fe90f9bf25c94269236cb5408e00e188` | 18 | | WETH | Wrapped Ethereum | `0xd0c1a714c46c364dbdd4e0f7b0b6ba5354460da7` | 18 | | USDT | Tether USD | `0x2a401fe7616c4aba69b147b4b725ce48ca7ec660` | 6 | | USDC | USD Coin | `0x29e1f94f6b209b57ecdc1fe87448a6d085a78a5a` | 6 | Click on any address to view the token contract on PaxScan. ## Integration Example Here's a complete example of integrating PaxDex into your dApp: ```typescript React + wagmi theme={null} import { useWriteContract, useReadContract } from 'wagmi'; import { parseEther } from 'viem'; const VAULT_ADDRESS = '0x49B0f9a0554da1A7243A9C8ac5B45245A66D90ff'; function SwapComponent() { const { writeContract } = useWriteContract(); async function handleSwap(tokenIn, tokenOut, amount, minAmountOut) { // First approve await writeContract({ address: tokenIn, abi: ERC20_ABI, functionName: 'approve', args: [VAULT_ADDRESS, amount], }); // Then swap await writeContract({ address: VAULT_ADDRESS, abi: VAULT_ABI, functionName: 'swapExactTokensForTokens', args: [tokenIn, tokenOut, amount, minAmountOut], }); } return ( ); } ``` ```javascript vanilla JavaScript theme={null} async function performSwap(signer, tokenIn, tokenOut, amount, minAmountOut) { const VAULT_ADDRESS = '0x49B0f9a0554da1A7243A9C8ac5B45245A66D90ff'; // Approve token const tokenContract = new ethers.Contract(tokenIn, ERC20_ABI, signer); const approveTx = await tokenContract.approve(VAULT_ADDRESS, amount); await approveTx.wait(); // Execute swap const vault = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, signer); const swapTx = await vault.swapExactTokensForTokens( tokenIn, tokenOut, amount, minAmountOut ); return await swapTx.wait(); } ``` ## Error Handling Common errors and their solutions: Make sure to approve the Vault contract before swapping: ```javascript theme={null} await tokenIn.approve(VAULT_ADDRESS, amountIn); ``` Increase the `minAmountOut` parameter or wait for better market conditions. The pool may not have enough liquidity for your swap. Try a smaller amount. Your swap would significantly impact the price. Consider splitting into smaller swaps. ## Resources Check API status View on PaxScan View on PaxScan Get help and support # Argus VM (AVM) Source: https://sidiorresearchlabs.mintlify.app/argus-vm Register-based virtual machine with 256-bit native arithmetic, deterministic gas metering, and the ArgLang smart-contract language ## Overview ArgusVM is a register-based virtual machine designed for HyperPaxeer's dual-VM architecture. It is the execution environment for the **Argus** capital-orchestration layer β€” a C++ runtime that handles risk engines, funded smart-wallet management, and capital allocation. Smart contracts are written in **ArgLang**, a statically typed language with Rust-inspired syntax that compiles to `.avm` bytecode. Faster execution than stack-based VMs (no push/pop overhead) First-class support for cryptographic operations Compatible with EVM but not dependent on it ## Core Design Principles * **Register-based** β€” 32 general-purpose 256-bit registers eliminate push/pop overhead * **256-bit native** β€” first-class support for cryptographic operations and large integers * **Deterministic** β€” guaranteed identical output for identical input across all nodes * **Gas-metered** β€” every operation has a fixed gas cost * **Sandboxed** β€” no host-system access except whitelisted syscalls ## Architecture ### Register Set ArgusVM uses 32 general-purpose 256-bit registers plus special-purpose registers: ```rust theme={null} // General-purpose registers (256-bit) r0-r31 : 32 general-purpose registers // Special-purpose registers (64-bit) pc : Program counter sp : Stack pointer (for call frames) fp : Frame pointer (for local variables) gas : Remaining gas status : Status flags ``` ### Status Flags 64-bit status register with condition flags: ``` bit 0: ZERO - Last operation result was zero bit 1: CARRY - Arithmetic carry occurred bit 2: OVERFLOW - Arithmetic overflow occurred bit 3: HALT - Execution halted bit 4: REVERT - Transaction should revert bit 5-63: Reserved ``` ## Memory Model ArgusVM uses a segmented memory model optimized for smart contracts: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” 0x00000000 β”‚ Code Segment β”‚ (Read-only, contract bytecode) β”‚ (Max 24KB) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ 0x00006000 β”‚ Data Segment β”‚ (Read/Write, initialized data) β”‚ (Max 8KB) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ 0x00008000 β”‚ Stack β”‚ (Read/Write, grows downward) β”‚ (Max 64KB) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ 0x00018000 β”‚ Heap β”‚ (Read/Write, dynamic allocation) β”‚ (Max 128KB) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ 0x00038000 ``` ### Storage (Persistent State) * **Key-value store**: `bytes32 β†’ bytes32` * **Accessed via**: `SLOAD` and `SSTORE` opcodes * **Gas costs**: * `SLOAD`: 200 gas (cold), 100 gas (warm) * `SSTORE`: 5000 gas (cold), 200 gas (warm) ## Instruction Set Architecture (ISA) ### Instruction Format Fixed-width 64-bit instructions: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ opcode β”‚ dst β”‚ src1 β”‚ src2 β”‚ immediate β”‚ β”‚ 8-bit β”‚ 8-bit β”‚ 8-bit β”‚ 8-bit β”‚ 32-bit β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Opcode Categories ```rust theme={null} 0x00 NOP - No operation 0x01 ADD dst, src1, src2 - dst = src1 + src2 0x02 SUB dst, src1, src2 - dst = src1 - src2 0x03 MUL dst, src1, src2 - dst = src1 * src2 0x04 DIV dst, src1, src2 - dst = src1 / src2 (unsigned) 0x05 SDIV dst, src1, src2 - dst = src1 / src2 (signed) 0x06 MOD dst, src1, src2 - dst = src1 % src2 0x07 EXP dst, src1, src2 - dst = src1 ** src2 0x08 ADDMOD dst, src1, src2 - dst = (src1 + src2) % imm 0x09 MULMOD dst, src1, src2 - dst = (src1 * src2) % imm ``` ```rust theme={null} 0x10 AND dst, src1, src2 - dst = src1 & src2 0x11 OR dst, src1, src2 - dst = src1 | src2 0x12 XOR dst, src1, src2 - dst = src1 ^ src2 0x13 NOT dst, src1 - dst = ~src1 0x14 SHL dst, src1, src2 - dst = src1 << src2 0x15 SHR dst, src1, src2 - dst = src1 >> src2 (logical) 0x16 SAR dst, src1, src2 - dst = src1 >> src2 (arithmetic) 0x17 ROL dst, src1, src2 - dst = rotate_left(src1, src2) 0x18 ROR dst, src1, src2 - dst = rotate_right(src1, src2) ``` ```rust theme={null} 0x20 LT dst, src1, src2 - dst = (src1 < src2) ? 1 : 0 0x21 GT dst, src1, src2 - dst = (src1 > src2) ? 1 : 0 0x22 EQ dst, src1, src2 - dst = (src1 == src2) ? 1 : 0 0x23 ISZERO dst, src1 - dst = (src1 == 0) ? 1 : 0 0x24 SLT dst, src1, src2 - dst = (src1 < src2) ? 1 : 0 (signed) 0x25 SGT dst, src1, src2 - dst = (src1 > src2) ? 1 : 0 (signed) ``` ```rust theme={null} 0x30 MLOAD dst, src1 - dst = memory[src1] 0x31 MSTORE src1, src2 - memory[src1] = src2 0x32 MLOAD8 dst, src1 - dst = memory[src1] (8-bit) 0x33 MSTORE8 src1, src2 - memory[src1] = src2 (8-bit) 0x34 MCOPY dst, src, len - memcpy(dst, src, len) ``` ```rust theme={null} 0x40 SLOAD dst, key - dst = storage[key] 0x41 SSTORE key, value - storage[key] = value ``` ```rust theme={null} 0x50 JMP addr - pc = addr 0x51 JMPI addr, cond - if (cond != 0) pc = addr 0x52 CALL addr - call subroutine at addr 0x53 RET - return from subroutine 0x54 HALT - stop execution (success) 0x55 REVERT - stop execution (revert state) ``` ```rust theme={null} 0x80 ADDRESS dst - dst = current contract address 0x81 BALANCE dst, addr - dst = balance of addr 0x82 ORIGIN dst - dst = transaction origin 0x83 CALLER dst - dst = message sender 0x84 CALLVALUE dst - dst = msg.value 0x85 CALLDATALOAD dst, idx - dst = calldata[idx] 0x86 CALLDATASIZE dst - dst = len(calldata) 0x87 CODESIZE dst - dst = len(code) 0x88 GASPRICE dst - dst = tx.gasprice 0x89 BLOCKHASH dst, num - dst = blockhash(num) 0x8A COINBASE dst - dst = block.coinbase 0x8B TIMESTAMP dst - dst = block.timestamp 0x8C NUMBER dst - dst = block.number 0x8D GASLIMIT dst - dst = block.gaslimit 0x8E CHAINID dst - dst = chain_id ``` ```rust theme={null} 0x90 EXTCALL addr, gas, value, argsOffset, argsSize, retOffset, retSize 0x91 EXTDELEGATECALL addr, gas, argsOffset, argsSize, retOffset, retSize 0x92 EXTSTATICCALL addr, gas, argsOffset, argsSize, retOffset, retSize 0x93 CREATE value, offset, size, salt 0x94 CREATE2 value, offset, size, salt 0x95 SELFDESTRUCT beneficiary ``` ## Gas Model ### Base Costs | Operation | Gas Cost | | -------------------- | ------------------------------------ | | Arithmetic | 3 gas | | Bitwise | 3 gas | | Comparison | 3 gas | | Memory load | 3 gas | | Memory store | 3 gas | | Storage load (cold) | 200 gas | | Storage load (warm) | 100 gas | | Storage store (cold) | 5000 gas | | Storage store (warm) | 200 gas | | Jump | 8 gas | | Call | 100 gas + target gas | | Create | 32000 gas | | Log | 375 gas + 375 per topic + 8 per byte | ### Memory Expansion Cost ``` memory_cost = (memory_size_word ** 2) / 512 + (3 * memory_size_word) ``` ## Execution Model ### Contract Execution Flow Load contract bytecode from state ```rust theme={null} pc = 0 gas = tx.gas_limit registers = [0; 32] memory = empty ``` Execute until HALT/REVERT/OUT\_OF\_GAS Return result + remaining gas + state changes ### Call Stack * **Max depth**: 1024 calls * **Each frame stores**: * Return address (pc) * Saved registers (r0-r31) * Local variables * Gas limit for this call ## Syscall Interface ArgusVM provides a syscall interface for cryptographic operations: | ID | Name | Input | Output | | -- | ----------------- | ---------------- | --------------- | | 0 | ecrecover | hash, v, r, s | address | | 1 | sha256 | data, len | hash | | 2 | keccak256 | data, len | hash | | 3 | blake2b | data, len | hash | | 4 | verify\_ed25519 | msg, sig, pubkey | bool | | 5 | verify\_secp256k1 | msg, sig, pubkey | bool | | 6 | bls\_verify | msg, sig, pubkey | bool | | 7 | bls\_aggregate | sigs\[], len | aggregated\_sig | | 8 | modexp | base, exp, mod | result | | 9 | bn256\_add | x1, y1, x2, y2 | x3, y3 | | 10 | bn256\_mul | x, y, scalar | x2, y2 | | 11 | bn256\_pairing | points\[], len | bool | ## Precompiled Contracts Standard precompiles for common cryptographic operations: | Address | Name | Purpose | | ------- | -------------- | ----------------------------------- | | 0x01 | ECRecover | ECDSA signature recovery | | 0x02 | SHA256 | SHA-256 hash | | 0x03 | RIPEMD160 | RIPEMD-160 hash | | 0x04 | Identity | Data copy | | 0x05 | ModExp | Modular exponentiation | | 0x06 | BN256Add | BN256 elliptic curve addition | | 0x07 | BN256Mul | BN256 elliptic curve multiplication | | 0x08 | BN256Pairing | BN256 pairing check | | 0x09 | Blake2F | Blake2b F compression | | 0x0A | BLS12Verify | BLS12-381 signature verification | | 0x0B | BLS12Aggregate | BLS12-381 signature aggregation | ## Bytecode Format ### File Structure ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚Magic Number (4 bytes)β”‚ 0x41564D00 ("AVM\0") β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Version (2 bytes) β”‚ 0x0001 β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Code Size (4 bytes) β”‚ Length of code section β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Data Size (4 bytes) β”‚ Length of data section β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Code Section β”‚ Executable instructions β”‚ (variable length) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Data Section β”‚ Initialized constants β”‚ (variable length) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Metadata Section β”‚ ABI, source map, etc. β”‚ (variable length) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Instruction Encoding Example ```rust theme={null} // Example: ADD r1, r2, r3 // Encoding: 0x01 0x01 0x02 0x03 0x00000000 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ opcode β”‚ dst β”‚ src1 β”‚ src2 β”‚ immediate β”‚ β”‚ 0x01 β”‚ 0x01 β”‚ 0x02 β”‚ 0x03 β”‚ 0x00000000 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ## Determinism Guarantees ### Prohibited (Non-Deterministic) The following are **prohibited** in ArgusVM contracts: * ❌ System time (use `block.timestamp`) * ❌ Random numbers (use `block.hash + nonce`) * ❌ Floating point (use fixed-point arithmetic) * ❌ Hash map iteration order (use sorted keys) * ❌ External I/O (only syscalls allowed) ### Enforced Determinism * βœ… All arithmetic is 256-bit integer (no floats) * βœ… Division by zero returns 0 (no exceptions) * βœ… Out-of-bounds memory access reverts * βœ… All randomness from blockchain state * βœ… Fixed gas costs per operation ## Security Features * No file system access * No network access * No system calls except whitelisted syscalls * Memory isolation between contracts * Prevents infinite loops * Prevents DoS attacks * Ensures bounded execution time * Call depth limit: 1024 * State changes committed only on success * Revert cascades up call stack * Built-in overflow checks * Safe arithmetic by default * No need for SafeMath library ## Performance Characteristics ### Expected Performance | Metric | Value | | -------------- | ---------------------------------------- | | **Throughput** | 10,000+ simple transactions/sec per core | | **Latency** | \<1ms per simple contract call | | **Memory** | \<100MB per VM instance | | **Startup** | \<10ms to initialize VM | ### Optimization Strategies * JIT compilation for hot paths (future) * Register allocation optimization * Instruction fusion (combine common patterns) * Lazy memory allocation ## Comparison to Other VMs | Feature | ArgusVM | EVM | WASM | | ------------------ | -------- | ------- | --------- | | **Architecture** | Register | Stack | Stack | | **Word Size** | 256-bit | 256-bit | 32/64-bit | | **Gas Metering** | Yes | Yes | External | | **Deterministic** | Yes | Yes | Depends | | **Precompiles** | Yes | Yes | No | | **JIT Support** | Future | No | Yes | | **EVM Compatible** | Yes | N/A | No | | **EVM Dependent** | **No** | **Yes** | No | **Key Differentiator:** ArgusVM is the only VM that is **EVM-compatible but not EVM-dependent**, enabling full ecosystem independence. ## EVM Compatibility Layer While ArgusVM is independent, we maintain full EVM compatibility through a translation layer: EVM bytecode can be translated to AVM bytecode: * Stack operations β†’ Register operations * EVM opcodes β†’ AVM opcodes * Gas costs normalized * Behavior preserved Existing Ethereum tooling works with ArgusVM: * Hardhat, Foundry, Remix support * MetaMask and other wallets * Block explorers * Bridge protocols Seamless migration for developers: 1. Deploy existing Solidity contracts (via translation) 2. Gradually migrate to ArgLang 3. Optimise for ArgusVM architecture 4. Leverage native performance benefits ## ArgLang ArgLang is the statically typed, contract-oriented language that compiles to AVM bytecode. It combines Rust-style safety with Solidity familiarity. ### Syntax ```arglang theme={null} contract HelloWorld { state greeting: string; init(initial_greeting: string) { greeting = initial_greeting; } pub fn set_greeting(new_greeting: string) { greeting = new_greeting; } pub view fn get_greeting() -> string { return greeting; } } ``` ### Type System * **Integers**: `u8`, `u16`, `u32`, `u64`, `u128`, `u256`, `i8` – `i256` * **Boolean**: `bool` * **Address**: `address` (20 bytes) * **Bytes**: `bytes1` – `bytes32`, `bytes`, `string` * **Collections**: `Vec`, `Map`, arrays (`u256[10]`), structs, enums, options ### Function Visibility ```arglang theme={null} pub fn public_function() { } // public, modifies state fn internal_function() { } // internal only pub view fn read_only() -> u256 { } // reads state, no mutation pub pure fn calculate(a: u256) -> u256 { } // no state access pub payable fn deposit() { } // can receive tokens ``` ### Control Flow ```arglang theme={null} if x > 10 { } else { } for i in 0..10 { } while condition { } match result { Result::Success(v) => { }, Result::Error(e) => { }, } ``` ### Built-in Globals * **msg**: `sender`, `value`, `data`, `sig` * **tx**: `origin`, `gasprice` * **block**: `number`, `timestamp`, `coinbase`, `gaslimit`, `chainid` * **this**: `address(this)`, `this.balance` ### Standard Library ```arglang theme={null} use std::math; // min, max, abs, pow, sqrt use std::crypto; // keccak256, sha256, ecrecover use std::collections; // Vec, Map, Set ``` ### Compiler Pipeline ``` ArgLang Source (.arg) ↓ Lexer (tokens) ↓ Parser (AST) ↓ Type Checker ↓ IR Generator ↓ Optimizer ↓ AVM Bytecode Generator ↓ ArgusVM Bytecode (.avm) ``` *** ## Map and Array Storage ArgLang maps and arrays use Keccak256-based slot hashing, similar to Solidity but adapted for register-based codegen: * **Simple state** β†’ sequential slots (`counter` at slot 0, `owner` at slot 1) * **Maps** β†’ `keccak256(key || base_slot)` * **Nested maps** β†’ recursive hashing: `keccak256(spender || keccak256(owner || base_slot))` * **Arrays** β†’ length at `base_slot`, element `i` at `keccak256(base_slot) + i` ### Gas for Map Operations | Operation | Gas | | --------------------------- | ------------------------- | | Map read (`balances[addr]`) | \~251 (KECCAK256 + SLOAD) | | Map write (warm) | \~5,251 | | Map write (cold) | \~20,251 | *** ## Resources Native fungible-token spec for ArgusVM Dual-VM design and precompile framework Deploy Solidity contracts on the EVM layer Spot exchange built on four AVM-adjacent precompiles # Architecture Overview Source: https://sidiorresearchlabs.mintlify.app/concepts/architecture/overview Dual-VM design, consensus model, custom precompiles, and module architecture of HyperPaxeer ## Overview HyperPaxeer is a sovereign Proof-of-Stake blockchain running on the **Alexandria Fork** (Cosmos SDK + CometBFT). It extends the standard EVM-on-Cosmos model with a second execution environment β€” the **Argus Virtual Machine (AVM)** β€” and four custom stateful/stateless precompiles that accelerate exchange-critical computation. *** ## Dual-VM Design ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ HyperPaxeer β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ EVM OS Layer β”‚ β”‚ Argus VM (AVM) β”‚ β”‚ β”‚ β”‚ Alexandria Fork │◄──►│ C++ runtime β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Solidity contracts β”‚ β”‚ ArgLang scripts (.arg) β”‚ β”‚ β”‚ β”‚ Custom precompiles β”‚ β”‚ Risk engine β”‚ β”‚ β”‚ β”‚ (0x901 – 0x904) β”‚ β”‚ Capital orchestration β”‚ β”‚ β”‚ β”‚ x/evm, x/erc20 modules β”‚ β”‚ Smart wallet lifecycle β”‚ β”‚ β”‚ β”‚ JSON-RPC / gRPC / REST β”‚ β”‚ .avm bytecode execution β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ CometBFT v0.38.15 Β· Cosmos SDK Β· IBC Β· x/paxoracle β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` * **EVM OS** β€” the blockchain shell: consensus, networking, EVM execution, standard Ethereum tooling * **AVM** β€” the value engine: capital allocation, drawdown policy, funded smart-wallet management * **Communication boundary** β€” on-chain interfaces `IPaxSpotReader` and `IAllowanceProvider` *** ## Consensus | Property | Value | | -------------- | ---------------------------------------------------- | | **Engine** | CometBFT v0.38.15 (Tendermint-based BFT) | | **Consensus** | Proof-of-Stake with instant finality | | **Block time** | 277 ms average, 341 ms p95 | | **Validators** | 10 active with 5.9%-13.1% voting-power range | | **Finality** | Single-block (no reorgs under 2/3 honest assumption) | CometBFT's `PrepareProposal` and `ProcessProposal` hooks allow validators to enforce fair transaction ordering at the consensus level β€” providing MEV protection without external infrastructure. *** ## Custom Precompiles Four precompiled contracts live at reserved addresses and execute native Go code at consensus speed: | Address | Name | Type | Purpose | | ------- | -------------------- | --------- | --------------------------------------------------------------- | | `0x901` | **OROBResolver** | Stateless | Convert basis-point offsets to absolute prices and back | | `0x902` | **BatchClearing** | Stateless | Compute uniform clearing price for sealed-bid auctions | | `0x903` | **OracleAggregator** | Stateful | Read/write validator price submissions via `x/paxoracle` keeper | | `0x904` | **PoFQScorer** | Stateless | Score fill quality against oracle at execution time | Precompiles use the HyperPaxeer stateful-precompile framework (`cmn.Precompile` embedded struct with `RunSetup` for SDK context access). Solidity interfaces are at `contracts/paxspot/src/interfaces/`. *** ## Cosmos SDK Modules ### Standard Modules (Alexandria Fork) `x/evm`, `x/erc20`, `x/feemarket`, `x/vesting`, `x/inflation`, `x/epochs`, `x/staking`, `x/distribution`, `x/gov`, `x/ibc` ### Custom Module: x/paxoracle Validator Oracle Module β€” validators submit prices via the `0x903` precompile's `submitPrice(bytes32, int256, uint256)` method. The module stores submissions in a KV store and aggregates them: * **GetMedianPrice**: filters stale submissions (>15 blocks), requires minimum quorum, computes confidence-weighted median * **IsValidator**: verifies submitter is an active validator via `x/staking` keeper * **Parameters**: `staleness_threshold` (default 15 blocks), `min_quorum` (default 1) *** ## Chain-Level Advantages These capabilities are possible because HyperPaxeer is a sovereign chain, not a shared L1/L2: 1. **Custom precompiles** β€” move expensive computation (batch clearing, oracle aggregation) to native Go. Near-zero gas for critical operations 2. **Transaction ordering control** β€” `PrepareProposal`/`ProcessProposal` enforce fair ordering. No front-running at the consensus level 3. **Native gas policy** β€” gas prices can be set to near-zero for exchange operations or subsidised for funded smart wallets 4. **IBC interoperability** β€” native token transfers from Osmosis, Injective, Noble (USDC), and other Cosmos chains. No bridges, no wrapping 5. **Validator-integrated keepers** β€” validators run keeper logic as sidecars, making conditional order execution a first-class chain service *** ## Node Architecture Nodes are deployed via the `hpx` CLI as Docker containers. Two node types: | Type | Purpose | Configuration | | ------------- | ---------------------------------------- | ---------------------------------------- | | **RPC** | Serve JSON-RPC, gRPC, REST, WebSocket | Full indexing, all endpoints exposed | | **Validator** | Produce blocks, participate in consensus | Default pruning, optimised for consensus | Each node runs under `/root/hyperpax-nodes//` with an FD Guardian sidecar that monitors file descriptors and auto-restarts on leak detection. ### Endpoints per Node | Protocol | Default Port | | -------------- | ------------ | | P2P | 26656 | | CometBFT RPC | 26657 | | REST API | 1317 | | gRPC | 9090 | | JSON-RPC (EVM) | 8545 | | WebSocket | 8546 | Ports auto-increment for multi-node deployments on a single server. *** ## Upgrade Process Network upgrades are coordinated across all validators: 1. Halt all validators at a target block height 2. Back up chain state from one validator 3. Distribute new binary as a Docker image 4. Fix any app-hash or priv\_validator mismatches 5. Restart all validators simultaneously The `hpx` CLI and `validate/upgrades/` docs cover automated and manual upgrade procedures. *** ## Resources Live validator health, node latency, and block timing Deploy RPC or Validator nodes with the hpx CLI Register architecture, ISA, gas model, and ArgLang Spot exchange leveraging all four precompiles # Network Configuration Source: https://sidiorresearchlabs.mintlify.app/configuration Configure HyperPaxeer in your applications using various libraries and frameworks ## Overview Configure HyperPaxeer in your applications using wagmi, viem, ethers.js, or web3.js. ## Network Details | Parameter | Value | | --------------- | ----------------------------------- | | Chain ID | `125` | | Network Name | Paxeer Network | | Native Currency | PAX (Paxeer) | | Decimals | 18 | | RPC Endpoint | `https://public-rpc.paxeer.app/rpc` | | Block Explorer | `https://paxscan.io` | | Explorer API | `https://paxscan.io/api` | ## Configuration by Library ### wagmi Configuration Setup HyperPaxeer with wagmi for React applications. ```typescript wagmi-config.ts theme={null} import { createConfig, http } from 'wagmi' import { defineChain } from 'viem' export const paxeer = defineChain({ id: 125, name: 'HyperPaxeer', network: 'paxeer', nativeCurrency: { decimals: 18, name: 'Paxeer', symbol: 'PAX', }, rpcUrls: { default: { http: ['https://public-rpc.paxeer.app/rpc'], }, public: { http: ['https://public-rpc.paxeer.app/rpc'], }, }, blockExplorers: { default: { name: 'PaxScan', url: 'https://paxscan.io', apiUrl: 'https://paxscan.io/api', }, }, }) export const config = createConfig({ chains: [paxeer], transports: { [paxeer.id]: http(), }, }) ``` ### Usage in React ```tsx App.tsx theme={null} import { WagmiProvider } from 'wagmi' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { config } from './wagmi-config' const queryClient = new QueryClient() function App() { return ( ) } ``` Install required packages: `npm install wagmi viem @tanstack/react-query` ### viem Configuration Setup HyperPaxeer with viem for TypeScript applications. ```typescript viem-config.ts theme={null} import { createPublicClient, http, defineChain } from 'viem' export const paxeer = defineChain({ id: 125, name: 'HyperPaxeer', network: 'paxeer', nativeCurrency: { decimals: 18, name: 'Paxeer', symbol: 'PAX', }, rpcUrls: { default: { http: ['https://public-rpc.paxeer.app/rpc'], }, }, blockExplorers: { default: { name: 'PaxScan', url: 'https://paxscan.io', }, }, }) export const publicClient = createPublicClient({ chain: paxeer, transport: http(), }) ``` ### Usage ```typescript theme={null} import { publicClient } from './viem-config' // Get block number const blockNumber = await publicClient.getBlockNumber() // Get balance const balance = await publicClient.getBalance({ address: '0x...', }) // Read contract const data = await publicClient.readContract({ address: '0x...', abi: contractAbi, functionName: 'balanceOf', args: ['0x...'], }) ``` Install viem: `npm install viem` ### ethers.js Configuration Setup HyperPaxeer with ethers.js v6. ```javascript ethers-config.js theme={null} import { ethers } from 'ethers' const paxeerNetwork = { chainId: 125, name: 'HyperPaxeer', } // Connect to HyperPaxeer const provider = new ethers.JsonRpcProvider( 'https://public-rpc.paxeer.app/rpc', paxeerNetwork ) export { provider } ``` ### Usage ```javascript theme={null} import { provider } from './ethers-config' // Get block number const blockNumber = await provider.getBlockNumber() console.log('Current block:', blockNumber) // Get balance const balance = await provider.getBalance('0x...') console.log('Balance:', ethers.formatEther(balance), 'HPX') // Get signer from MetaMask const signer = await provider.getSigner() // Send transaction const tx = await signer.sendTransaction({ to: '0x...', value: ethers.parseEther('1.0'), }) await tx.wait() // Interact with contract const contract = new ethers.Contract( contractAddress, contractABI, signer ) await contract.transfer('0x...', ethers.parseEther('10')) ``` Install ethers: `npm install ethers@6` ### web3.js Configuration Setup HyperPaxeer with web3.js v4. ```javascript web3-config.js theme={null} import Web3 from 'web3' // Connect to HyperPaxeer const web3 = new Web3('https://public-rpc.paxeer.app/rpc') export { web3 } ``` ### Usage ```javascript theme={null} import { web3 } from './web3-config' // Get network ID const networkId = await web3.eth.net.getId() console.log('Network ID:', networkId) // 125 // Get current block number const blockNumber = await web3.eth.getBlockNumber() console.log('Current block:', blockNumber) // Get balance const balance = await web3.eth.getBalance(address) console.log('Balance:', web3.utils.fromWei(balance, 'ether'), 'HPX') // Send transaction const receipt = await web3.eth.sendTransaction({ from: fromAddress, to: toAddress, value: web3.utils.toWei('1', 'ether'), }) // Interact with contract const contract = new web3.eth.Contract(contractABI, contractAddress) await contract.methods.transfer(toAddress, amount).send({ from: fromAddress, }) ``` Install web3.js: `npm install web3@4` ## MetaMask Configuration Add HyperPaxeer to MetaMask programmatically: ```javascript theme={null} async function addPaxeerNetwork() { try { await window.ethereum.request({ method: 'wallet_addEthereumChain', params: [ { chainId: '0xe5', // 125 in hex chainName: 'HyperPaxeer', nativeCurrency: { name: 'HyperPaxeer', symbol: 'HPX', decimals: 18, }, rpcUrls: ['https://public-rpc.paxeer.app/rpc'], blockExplorerUrls: ['https://paxscan.io'], }, ], }); console.log('HyperPaxeer added to MetaMask'); } catch (error) { console.error('Error adding network:', error); } } ``` ## Environment Variables Store your configuration in environment variables: ```bash .env theme={null} # HyperPaxeer Configuration PAXEER_RPC_URL=https://public-rpc.paxeer.app/rpc PAXEER_CHAIN_ID=125 PAXEER_EXPLORER=https://paxscan.io # Your private key (NEVER commit this!) PRIVATE_KEY=your_private_key_here ``` Never commit private keys or sensitive credentials to version control. Use environment variables and add `.env` to your `.gitignore`. ## Hardhat Configuration ```javascript hardhat.config.js theme={null} require("@nomicfoundation/hardhat-toolbox"); require('dotenv').config(); module.exports = { solidity: "0.8.20", networks: { paxeer: { url: process.env.PAXEER_RPC_URL, chainId: parseInt(process.env.PAXEER_CHAIN_ID), accounts: [process.env.PRIVATE_KEY], }, }, etherscan: { apiKey: { paxeer: process.env.ETHERSCAN_API_KEY || "YOUR_API_KEY", }, customChains: [ { network: "paxeer", chainId: 125, urls: { apiURL: "https://paxscan.io/api", browserURL: "https://paxscan.io", }, }, ], }, }; ``` ## Foundry Configuration ```toml foundry.toml theme={null} [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}", url = "https://paxscan.io/api" } ``` ## Testing Connection Verify your configuration is working: ```typescript TypeScript theme={null} import { publicClient } from './viem-config' async function testConnection() { try { const blockNumber = await publicClient.getBlockNumber() console.log('βœ… Connected! Current block:', blockNumber) console.log('βœ… Chain ID:', publicClient.chain.id) } catch (error) { console.error('❌ Connection failed:', error) } } testConnection() ``` ```javascript JavaScript theme={null} import { provider } from './ethers-config' async function testConnection() { try { const network = await provider.getNetwork() const blockNumber = await provider.getBlockNumber() console.log('βœ… Connected! Chain ID:', network.chainId) console.log('βœ… Current block:', blockNumber) } catch (error) { console.error('❌ Connection failed:', error) } } testConnection() ``` ```python Python theme={null} from web3 import Web3 w3 = Web3(Web3.HTTPProvider('https://public-rpc.paxeer.app/rpc')) if w3.is_connected(): print(f'βœ… Connected! Chain ID: {w3.eth.chain_id}') print(f'βœ… Current block: {w3.eth.block_number}') else: print('❌ Connection failed') ``` ## Next Steps Follow our getting started guide Deploy and interact with contracts View complete integration examples Explore all available RPC methods # Smart Contracts Source: https://sidiorresearchlabs.mintlify.app/contracts Deploy, verify, and interact with Solidity contracts on HyperPaxeer HyperPaxeer is fully EVM-compatible. Running on the **Alexandria Fork** with **Hyperpax-OS Cronos**, all standard Ethereum tooling works β€” Foundry, Hardhat, Remix, ethers.js, wagmi, and viem. Use `--legacy --slow` flags with Foundry for reliable transaction inclusion. ## Overview Deploy and interact with smart contracts on HyperPaxeer (Chain ID `125`). Foundry is the recommended framework; Hardhat and Remix are also supported. ## Deployment Options ### Deploy with Hardhat Configure Hardhat to deploy on HyperPaxeer. #### 1. Install dependencies ```bash theme={null} npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox ``` #### 2. Configure hardhat.config.js ```javascript hardhat.config.js theme={null} require("@nomicfoundation/hardhat-toolbox"); module.exports = { solidity: "0.8.20", networks: { paxeer: { url: "https://public-rpc.paxeer.app/rpc", chainId: 125, accounts: [process.env.PRIVATE_KEY] } }, etherscan: { apiKey: { hyperpaxeer: "any-string" }, customChains: [ { network: "hyperpaxeer", chainId: 125, urls: { apiURL: "https://paxscan.io/api", browserURL: "https://paxscan.io" } } ] } }; ``` #### 3. Deploy ```bash theme={null} npx hardhat run scripts/deploy.js --network hyperpaxeer ``` Store your private key in a `.env` file and never commit it to version control. ### Deploy with Foundry Use Foundry to deploy contracts on HyperPaxeer. #### 1. Install Foundry ```bash theme={null} curl -L https://foundry.paradigm.xyz | bash foundryup ``` #### 2. Create project ```bash theme={null} forge init my-project cd my-project ``` #### 3. Deploy ```bash theme={null} forge create src/MyContract.sol:MyContract \ --rpc-url https://public-rpc.paxeer.app/rpc \ --private-key $PRIVATE_KEY \ --legacy --slow ``` Use `--verify` flag to verify your contract on PaxScan after deployment. ### Deploy with Remix Use Remix IDE to deploy contracts via MetaMask. Go to [remix.ethereum.org](https://remix.ethereum.org) Write or import your Solidity contract in the file explorer Use the Solidity compiler to compile your contract Connect MetaMask to HyperPaxeer (Chain ID: 125) In the Deploy & Run tab, select "Injected Provider - MetaMask" Click "Deploy" and confirm the transaction in MetaMask Make sure your MetaMask is connected to HyperPaxeer (Chain ID 125) before deploying. ## Example Contract Here's a simple ERC-20 token contract example: ```solidity MyToken.sol theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MyToken is ERC20 { constructor() ERC20("MyToken", "MTK") { _mint(msg.sender, 1000000 * 10 ** decimals()); } } ``` ### Deploying the Example ```javascript scripts/deploy.js theme={null} const hre = require("hardhat"); async function main() { const MyToken = await hre.ethers.getContractFactory("MyToken"); const token = await MyToken.deploy(); await token.waitForDeployment(); console.log("MyToken deployed to:", await token.getAddress()); } main().catch((error) => { console.error(error); process.exitCode = 1; }); ``` Run the deployment: ```bash theme={null} npx hardhat run scripts/deploy.js --network paxeer ``` ```bash theme={null} forge create src/MyToken.sol:MyToken \ --rpc-url https://public-rpc.paxeer.app/rpc \ --private-key $PRIVATE_KEY \ --chain-id 125 ``` ## Verifying Contracts After deployment, verify your contract on PaxScan for transparency and easier interaction. ### Using Hardhat ```bash theme={null} npx hardhat verify --network paxeer DEPLOYED_CONTRACT_ADDRESS ``` ### Using Foundry ```bash theme={null} forge verify-contract \ --chain-id 125 \ --compiler-version v0.8.20 \ DEPLOYED_CONTRACT_ADDRESS \ src/MyToken.sol:MyToken \ --etherscan-api-key YOUR_API_KEY ``` ## Interacting with Contracts ### Using ethers.js ```javascript theme={null} import { ethers } from 'ethers'; const provider = new ethers.JsonRpcProvider( 'https://public-rpc.paxeer.app/rpc' ); const contract = new ethers.Contract( contractAddress, contractABI, provider ); // Read contract data const balance = await contract.balanceOf(address); // Write contract data (requires signer) const signer = await provider.getSigner(); const contractWithSigner = contract.connect(signer); await contractWithSigner.transfer(recipientAddress, amount); ``` ### Using wagmi ```typescript theme={null} import { useReadContract, useWriteContract } from 'wagmi'; // Read contract const { data: balance } = useReadContract({ address: '0x...', abi: tokenABI, functionName: 'balanceOf', args: [userAddress], }); // Write contract const { writeContract } = useWriteContract(); function transfer() { writeContract({ address: '0x...', abi: tokenABI, functionName: 'transfer', args: [recipientAddress, amount], }); } ``` ## Best Practices * Use appropriate data types (uint256 vs uint8) * Minimize storage writes * Use events for logging instead of storage * Batch operations when possible * Use OpenZeppelin contracts for standards * Implement access control * Validate all inputs * Test thoroughly before mainnet deployment * Consider getting an audit for critical contracts * Write comprehensive unit tests * Test locally or on private networks before mainnet * Test edge cases and failure scenarios * Use fuzzing for complex contracts ## Network Information | Parameter | Value | | -------------- | ----------------------------------- | | Network Name | HyperPaxeer | | RPC URL | `https://public-rpc.paxeer.app/rpc` | | Chain ID | `125` | | Currency | HPX (`ahpx`, 18 decimals) | | Block Explorer | `https://paxscan.io` | ## Next Steps Configure different libraries for HyperPaxeer View complete integration examples Explore all available RPC methods Recommended SDKs and development tools # Computable Token Machine (CTM) Source: https://sidiorresearchlabs.mintlify.app/ctm Revolutionary token standard where tokens are fully-fledged execution environments ## Overview The Computable Token Machine is a revolutionary token standard that combines ERC-20 functionality with the Diamond Standard (EIP-2535). Each CTM is both a standard token AND a modular execution environment capable of running its own applications, managing state, and evolving over time. **Beyond value, beyond utilityβ€”tokens that think.** Modular architecture Infinite extensibility Self-executing logic ## Live Contract **Address:** `0x477A9f214c947e6D81b9d32b6b1883F4a4ffFb24` [View on PaxScan β†’](https://paxscan.io/address/0x477A9f214c947e6D81b9d32b6b1883F4a4ffFb24) ## What is CTM? The Computable Token Machine is a revolutionary token standard that combines ERC-20 functionality with the Diamond Standard (EIP-2535). Each CTM is both a standard token AND a modular execution environment capable of running its own applications, managing state, and evolving over time. ## Key Features Add new features and applications to your token after deployment. Your token evolves with your needs. All Programs share the same storage context. Programs can read and interact with each other seamlessly. Modular Programs optimize gas usage and bypass EVM contract size limits. Create complex on-chain agents that manage assets and execute tasks based on rich internal state. ## Core Concepts ### Two Personalities CTM acts as both a token and a machine: On the outside, a CTM behaves like any standard ERC-20 token. It can be: * Held in wallets * Traded on exchanges * Used in DeFi protocols * Transferred between addresses No special handling required - it's just a token! Internally, the CTM acts as a proxy that routes function calls to various logic contracts called "Programs" (or Facets). These Programs can be: * Added without redeployment * Replaced to fix bugs or add features * Removed when no longer needed * Composed together for complex behavior All while maintaining the same contract address! ### Programs (Facets) Programs are stateless Solidity contracts that contain the logic executed by the CTM. Each Program manages its own state within a unique storage slot to prevent collisions. **Example Programs:** * Voting and Governance * Staking and Rewards * DEX Integration * NFT Minting * Custom Game Logic * Automated Trading * On-chain AI Agents ### Diamond Standard (EIP-2535) CTM is built on the Diamond Standard, which allows a single contract to use multiple logic contracts (facets/programs). This pattern enables: * βœ… Unlimited contract size * βœ… Upgradability * βœ… Modular functionality * βœ… Single address persistence ## Quick Start ```bash theme={null} npm i @paxeer-foundation/ctm-contracts # Or clone directly: git clone https://github.com/Paxeer-Network/Pax-v3-coreCTM.git cd Pax-v3-coreCTM npm install ``` Add HyperPaxeer details to `hardhat.config.js`: ```javascript hardhat.config.js theme={null} networks: { paxeer: { url: "https://public-rpc.paxeer.app/rpc", chainId: 125, accounts: [process.env.PRIVATE_KEY] // HyperPaxeer mainnet } } ``` ```bash theme={null} npx hardhat run scripts/deploy.js --network paxeer ``` This deploys: * TokenVM.sol (the main proxy contract) * DiamondCutFacet (for adding/removing Programs) * DiamondLoupeFacet (for inspecting installed Programs) * OwnershipFacet (access control) * ERC20Facet (token functionality) ## Creating Programs ### Program Structure Programs must be stateless and manage state within a unique storage slot to prevent collisions. ```solidity VotingProgram.sol theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC20Facet} from "./ERC20Facet.sol"; contract VotingProgram { struct VotingStorage { mapping(uint256 => string) proposals; mapping(uint256 => mapping(address => uint256)) votes; uint256 proposalCount; } bytes32 constant VOTING_STORAGE_POSITION = keccak256("ctm.program.storage.voting"); function votingStorage() internal pure returns (VotingStorage storage vs) { bytes32 position = VOTING_STORAGE_POSITION; assembly { vs.slot := position } } function createProposal(string calldata _description) external { VotingStorage storage vs = votingStorage(); vs.proposalCount++; vs.proposals[vs.proposalCount] = _description; } function vote(uint256 _proposalId) external { uint256 voterBalance = ERC20Facet(address(this)) .balanceOf(msg.sender); require(voterBalance > 0, "Must hold tokens"); VotingStorage storage vs = votingStorage(); vs.votes[_proposalId][msg.sender] = voterBalance; } function getProposal(uint256 _proposalId) external view returns (string memory) { VotingStorage storage vs = votingStorage(); return vs.proposals[_proposalId]; } function getVotes(uint256 _proposalId, address _voter) external view returns (uint256) { VotingStorage storage vs = votingStorage(); return vs.votes[_proposalId][_voter]; } } ``` ### Adding Programs to CTM Use the `diamondCut` function to register new Programs: ```javascript theme={null} const diamondCut = await ethers.getContractAt('IDiamondCut', ctmAddress); await diamondCut.diamondCut( [{ facetAddress: votingProgramAddress, action: FacetCutAction.Add, // 0 = Add, 1 = Replace, 2 = Remove functionSelectors: getSelectors(votingProgram) }], ethers.constants.AddressZero, '0x' ); ``` ### Helper Function for Selectors ```javascript theme={null} function getSelectors(contract) { const signatures = Object.keys(contract.interface.functions); const selectors = signatures.reduce((acc, val) => { if (val !== 'init(bytes)') { acc.push(contract.interface.getSighash(val)); } return acc; }, []); return selectors; } ``` ## Program Best Practices Always use keccak256 hashes for storage positions to avoid collisions: ```solidity theme={null} bytes32 constant STORAGE_POSITION = keccak256("ctm.program.storage.myprogram"); ``` Never use regular state variables at the contract level! Programs should not hold funds or use constructors that set state: ❌ **Wrong:** ```solidity theme={null} contract MyProgram { uint256 public count = 0; // Don't do this! constructor() { count = 10; // Don't do this! } } ``` βœ… **Correct:** ```solidity theme={null} contract MyProgram { bytes32 constant STORAGE_POSITION = keccak256("ctm.myprogram"); struct MyStorage { uint256 count; } function myStorage() internal pure returns (MyStorage storage ms) { bytes32 position = STORAGE_POSITION; assembly { ms.slot := position } } } ``` Protect diamondCut with ownership or governance controls: ```solidity theme={null} modifier onlyOwner() { require(msg.sender == owner(), "Not authorized"); _; } ``` Only authorized addresses should be able to add/remove Programs. Programs can call each other using address(this) and shared storage: ```solidity theme={null} // Calling another program's function uint256 balance = ERC20Facet(address(this)).balanceOf(user); // Reading shared storage (if designed that way) bytes32 sharedPosition = keccak256("ctm.shared.data"); ``` ## Security Considerations **Critical Security Points:** 1. **Storage Layout:** Never use standard global state variables. Always use the diamond storage pattern with unique keccak256 slots. 2. **Access Control:** The `diamondCut` function is extremely powerful. Ensure it's protected by robust ownership or governance control. 3. **Stateless Logic:** Programs are logic contracts and should not hold funds or have constructors that set state. 4. **Testing:** Thoroughly test all Programs before deployment. Once added to a CTM, they have access to the token's storage and capabilities. ## Auditing Checklist Before deploying CTM or adding new Programs: * [ ] Storage slots use unique keccak256 hashes * [ ] No global state variables in Programs * [ ] Access control properly configured * [ ] Programs don't hold funds directly * [ ] All Programs thoroughly tested * [ ] diamondCut function is protected * [ ] Inter-program interactions tested * [ ] Gas optimization reviewed * [ ] Security audit completed (for production) ## Advanced Examples ### Staking Program ```solidity theme={null} contract StakingProgram { struct StakingStorage { mapping(address => uint256) stakedAmount; mapping(address => uint256) stakingTimestamp; uint256 rewardRate; // rewards per second } bytes32 constant STAKING_STORAGE = keccak256("ctm.program.staking"); function stakingStorage() internal pure returns (StakingStorage storage ss) { bytes32 position = STAKING_STORAGE; assembly { ss.slot := position } } function stake(uint256 amount) external { ERC20Facet token = ERC20Facet(address(this)); require(token.transferFrom(msg.sender, address(this), amount), "Transfer failed"); StakingStorage storage ss = stakingStorage(); ss.stakedAmount[msg.sender] += amount; ss.stakingTimestamp[msg.sender] = block.timestamp; } function unstake(uint256 amount) external { StakingStorage storage ss = stakingStorage(); require(ss.stakedAmount[msg.sender] >= amount, "Insufficient stake"); uint256 rewards = calculateRewards(msg.sender); ss.stakedAmount[msg.sender] -= amount; ERC20Facet token = ERC20Facet(address(this)); require(token.transfer(msg.sender, amount + rewards), "Transfer failed"); } function calculateRewards(address user) public view returns (uint256) { StakingStorage storage ss = stakingStorage(); uint256 timeStaked = block.timestamp - ss.stakingTimestamp[user]; return ss.stakedAmount[user] * ss.rewardRate * timeStaked / 1e18; } } ``` ### Governance Program ```solidity theme={null} contract GovernanceProgram { struct GovernanceStorage { mapping(uint256 => Proposal) proposals; uint256 proposalCount; uint256 votingPeriod; } struct Proposal { string description; uint256 forVotes; uint256 againstVotes; uint256 endTime; bool executed; } bytes32 constant GOVERNANCE_STORAGE = keccak256("ctm.program.governance"); function governanceStorage() internal pure returns (GovernanceStorage storage gs) { bytes32 position = GOVERNANCE_STORAGE; assembly { gs.slot := position } } function propose(string calldata description) external returns (uint256) { GovernanceStorage storage gs = governanceStorage(); gs.proposalCount++; gs.proposals[gs.proposalCount] = Proposal({ description: description, forVotes: 0, againstVotes: 0, endTime: block.timestamp + gs.votingPeriod, executed: false }); return gs.proposalCount; } function vote(uint256 proposalId, bool support) external { GovernanceStorage storage gs = governanceStorage(); Proposal storage proposal = gs.proposals[proposalId]; require(block.timestamp < proposal.endTime, "Voting ended"); uint256 weight = ERC20Facet(address(this)).balanceOf(msg.sender); if (support) { proposal.forVotes += weight; } else { proposal.againstVotes += weight; } } } ``` ## Resources View source code and examples Explore on PaxScan Learn about Diamond Standard Join other CTM developers ## Next Steps Follow the deployment guide Build your own logic modules General contract deployment Set up your development environment # Current Network Facts Source: https://sidiorresearchlabs.mintlify.app/current-network Canonical mainnet identifiers, endpoints, binary, token denominations, and live precompile addresses ## HyperPaxeer mainnet Use this page as the source of truth for current network constants. HyperPaxeer currently operates mainnet only. There is no public testnet because Argus VM infrastructure is expensive to operate continuously. | Field | Value | | --------------------- | ------------------------------------------------------------------------- | | Network name | HyperPaxeer mainnet | | Cosmos chain ID | `hyperpax_125-1` | | EVM chain ID | `125` | | Public binary | `hyperpaxd_2.0.3` | | Runtime source | `hyperpaxeer-os` with custom precompiles from `hyperpax-os-cronosRelease` | | JSON-RPC | `https://public-rpc.paxeer.app/rpc` | | CometBFT RPC | `https://public-rpc.paxeer.app:26657` | | REST API | `https://public-rpc.paxeer.app:1317` | | gRPC | `https://public-rpc.paxeer.app:9090` | | Block explorer | `https://paxscan.io` | | Native display symbol | `PAX` / `hpx` | | Base denomination | `ahpx` | | Decimals | `18` | | Bech32 prefix | `pax` | | HD path | BIP44 coin type `60` | ## Wallet configuration | Field | Value | | --------------- | ----------------------------------- | | Network name | `HyperPaxeer` | | RPC URL | `https://public-rpc.paxeer.app/rpc` | | Chain ID | `125` | | Currency symbol | `HPX` | | Block explorer | `https://paxscan.io` | ```typescript wagmi-config.ts theme={null} import { createConfig, http } from 'wagmi' import { defineChain } from 'viem' export const hyperpaxeer = defineChain({ id: 125, name: 'HyperPaxeer', nativeCurrency: { decimals: 18, name: 'HyperPaxeer', symbol: 'PAX' }, rpcUrls: { default: { http: ['https://public-rpc.paxeer.app/rpc'] }, }, blockExplorers: { default: { name: 'PaxScan', url: 'https://paxscan.io' }, }, }) export const config = createConfig({ chains: [hyperpaxeer], transports: { [hyperpaxeer.id]: http() }, }) ``` ## Live EVM extensions | Address | Name | Stateful | Mainnet status | | -------------------------------------------- | ------------------------------ | -------: | -------------- | | `0x0000000000000000000000000000000000000400` | Bech32 encoding | No | Active | | `0x0000000000000000000000000000000000000901` | PaxSpot OROBResolver | No | Active | | `0x0000000000000000000000000000000000000902` | PaxSpot BatchClearing | No | Active | | `0x0000000000000000000000000000000000000903` | PaxSpot OracleAggregator / VOM | Mixed | Active | | `0x0000000000000000000000000000000000000904` | PaxSpot PoFQScorer | No | Active | ## Development notes * Use local EVM development networks for pre-mainnet contract testing. * Use mainnet RPC only when you are ready to interact with production HyperPaxeer state. * Store private keys in `.env` files or wallet-managed signers. Never commit secrets. * Use `paxscan.io` for explorer links in public docs and applications. # API Source: https://sidiorresearchlabs.mintlify.app/develop/api/index Public API endpoints and client libraries for HyperPaxeer. # API The following API's are recommended for development purposes. For maximum control and reliability it's recommended to run your own node. ## Networks Quickly connect your app or client to HyperPaxeer mainnet and public testnets. Head over to [Networks](./api/networks) to find a list of publicly available endpoints that you can use to connect to the HyperPaxeer ## Clients The HyperPaxeer supports different clients in order to support Cosmos and Ethereum transactions and queries. You can use Swagger as a REST interface for state queries and transactions: | | Description | Default Port | Swagger | | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------ | --------------------------------------------------------------------------- | | **Cosmos [gRPC](./cosmos-grpc.md#cosmos-grpc)** | Query or send HyperPaxeer transactions using gRPC | `9090` | | | **Cosmos REST ([gRPC-Gateway](./cosmos-grpc.md#cosmos-http-rest-grpc-gateway))** | Query or send HyperPaxeer transactions using an HTTP RESTful API | `9091` | [Testnet](https://api.hyperpaxd.dev/) [Mainnet](https://api.hyperpaxd.org/) | | **Ethereum [JSON-RPC](./ethereum-json-rpc/index.md)** | Query Ethereum-formatted transactions and blocks or send Ethereum txs using JSON-RPC | `8545` | | | **Ethereum [Websocket](./ethereum-json-rpc/index.md#ethereum-websocket)** | Subscribe to Ethereum logs and events emitted in smart contracts. | `8586` | | | **Tendermint [RPC](#tendermint-rpc)** | Query transactions, blocks, consensus state, broadcast transactions, etc. | `26657` | [Localhost](https://docs.tendermint.com/v0.34/rpc/) | | **Tendermint [Websocket](#tendermint-websocket)** | Subscribe to Tendermint ABCI events | `26657` | | | **Command Line Interface ([CLI](../../protocol/Paxeer-Network-cli))** | Query or send HyperPaxeer transactions using your Terminal or Console. | N/A | | # Networks Source: https://sidiorresearchlabs.mintlify.app/develop/api/networks # Networks ## Public Available Endpoints Below is a list of publicly available endpoints that you can use to connect to HyperPaxeer mainnet. :::tip You can also use [chainlist.org](https://chainlist.org/) to add the node directly to [Metamask](https://academy.evmosd.org/articles/beginner/connect-your-wallet/metamask). ::: :::note If you are searching for the protobuf interfaces, head over [here](https://buf.build/Paxeer-Network). ::: | Address | Category | Maintainer | Node Type | | ------------------------------------- | --------------------- | -------------- | --------- | | `https://public-rpc.paxeer.app/rpc` | `Ethereum` `JSON-RPC` | Paxeer Network | Public | | `https://public-rpc.paxeer.app:26657` | `CometBFT` `RPC` | Paxeer Network | Public | | `https://public-rpc.paxeer.app:1317` | `Cosmos` `REST` | Paxeer Network | Public | | `https://public-rpc.paxeer.app:9090` | `Cosmos` `gRPC` | Paxeer Network | Public | :::note HyperPaxeer currently operates mainnet only. There is no public testnet. ::: ## On-Demand Services ### Lava Lava is an open source protocol that serves as a p2p market for blockchain RPC & APIs. It gives wallets, dapps and indexers the most reliable RPC by optimally routing requests through a globally distributed network of node providers. In simpler words, Lava pairs consumers and providers of RPC in a similar way to how Uber connects passengers and drivers. Users of Lava enjoy top quality of service and data reliability & accuracy, ensured by Lava protocol and the crypto-economic framework In partnership with HyperPaxeer, Lava is the providing a highly reliable, community-powered free public endpoints you can find above. If you’re looking for higher rate-limits and usage analytics, [check out the Lava Gateway](https://gateway.lavanet.xyz?utm_source=HyperPaxeer-docs\&utm_medium=referral\&utm_campaign=HyperPaxeer-iprpc). # Tendermint rpc Source: https://sidiorresearchlabs.mintlify.app/develop/api/tendermint-rpc # Tendermint RPC The Tendermint RPC allows you to query transactions, blocks, consensus state, broadcast transactions, etc. The latest Tendermint RPC documentations can be found [here](https://docs.tendermint.com/v0.34/rpc/). Tendermint supports the following RPC protocols: * URI over HTTP * JSON-RPC over HTTP * JSON-RPC over Websockets The docs will contain an interactive Swagger interface. ## URI/HTTP A GET request with arguments encoded as query parameters: ``` curl localhost:26657/block?height=5 ``` ## RPC/HTTP JSONRPC requests can be POST'd to the root RPC endpoint via HTTP. See the list of supported Tendermint RPC endpoints using Swagger [here](../api#clients). ## RPC/Websocket ### Cosmos and Tendermint Events `Event`s are objects that contain information about the execution of the application and are triggered after a block is committed. They are mainly used by service providers like block explorers and wallet to track the execution of various messages and index transactions. You can get the full list of `event` categories and values [here](#list-of-tendermint-events). More on Events: * [Cosmos SDK Events](https://docs.cosmos.network/main/learn/advanced/events) ### Subscribing to Events via Websocket Tendermint Core provides a [Websocket](https://docs.tendermint.com/v0.34/tendermint-core/subscription.html) connection to subscribe or unsubscribe to Tendermint `Events`. To start a connection with the Tendermint websocket you need to define the address with the `--rpc.laddr` flag when starting the node (default `tcp://127.0.0.1:26657`): ```bash theme={null} hyperpaxd start --rpc.laddr="tcp://127.0.0.1:26657" ``` Then, start a websocket subscription with [ws](https://github.com/hashrocket/ws) ```bash theme={null} # connect to tendermint websocket at port 8080 ws ws://localhost:8080/websocket # subscribe to new Tendermint block headers > { "jsonrpc": "2.0", "method": "subscribe", "params": ["tm.event='NewBlockHeader'"], "id": 1 } ``` The `type` and `attribute` value of the `query` allow you to filter the specific `event` you are looking for. For example, an Ethereum transaction on HyperPaxeer (`MsgEthereumTx`) triggers an `event` of type `ethermint` and has `sender` and `recipient` as `attributes`. Subscribing to this `event` would be done like so: ```json theme={null} { "jsonrpc": "2.0", "method": "subscribe", "id": "0", "params": { "query": "tm.event='Tx' AND ethereum.recipient='hexAddress'" } } ``` where `hexAddress` is an Ethereum hex address (eg: `0x1122334455667788990011223344556677889900`). The generic syntax looks like this: ```json theme={null} { "jsonrpc": "2.0", "method": "subscribe", "id": "0", "params": { "query": "tm.event='' AND eventType.eventAttribute=''" } } ``` ### List of Tendermint Events The main events you can subscribe to are: * `NewBlock`: Contains `events` triggered during `BeginBlock` and `EndBlock`. * `Tx`: Contains `events` triggered during `DeliverTx` (i.e. transaction processing). * `ValidatorSetUpdates`: Contains validator set updates for the block. :::tip πŸ‘‰ The list of events types and values for each Cosmos SDK module can be found in the [Modules Specification](./../../../../protocol/modules/) section. Check the `Events` page to obtain the event list of each supported module on HyperPaxeer. ::: List of all Tendermint event keys: | | Event Type | Categories | | ---------------------------------------------------- | ---------------- | ----------- | | Subscribe to a specific event | `"tm.event"` | `block` | | Subscribe to a specific transaction | `"tx.hash"` | `block` | | Subscribe to transactions at a specific block height | `"tx.height"` | `block` | | Index `BeginBlock` and `Endblock` events | `"block.height"` | `block` | | Subscribe to ABCI `BeginBlock` events | `"begin_block"` | `block` | | Subscribe to ABCI `EndBlock` events | `"end_block"` | `consensus` | Below is a list of values that you can use to subscribe for the `tm.event` type: | | Event Value | Categories | | ---------------------- | ----------------------- | ----------- | | New block | `"NewBlock"` | `block` | | New block header | `"NewBlockHeader"` | `block` | | New Byzantine Evidence | `"NewEvidence"` | `block` | | New transaction | `"Tx"` | `block` | | Validator set updated | `"ValidatorSetUpdates"` | `block` | | Block sync status | `"BlockSyncStatus"` | `consensus` | | lock | `"Lock"` | `consensus` | | New consensus round | `"NewRound"` | `consensus` | | Polka | `"Polka"` | `consensus` | | Relock | `"Relock"` | `consensus` | | State sync status | `"StateSyncStatus"` | `consensus` | | Timeout propose | `"TimeoutPropose"` | `consensus` | | Timeout wait | `"TimeoutWait"` | `consensus` | | Unlock | `"Unlock"` | `consensus` | | Block is valid | `"ValidBlock"` | `consensus` | | Consensus vote | `"Vote"` | `consensus` | ### Example ```bash theme={null} ws ws://localhost:26657/websocket > { "jsonrpc": "2.0", "method": "subscribe", "params": ["tm.event='ValidatorSetUpdates'"], "id": 1 } ``` Example response: ```json theme={null} { "jsonrpc": "2.0", "id": 0, "result": { "query": "tm.event='ValidatorSetUpdates'", "data": { "type": "tendermint/event/ValidatorSetUpdates", "value": { "validator_updates": [ { "address": "09EAD022FD25DE3A02E64B0FE9610B1417183EE4", "pub_key": { "type": "tendermint/PubKeyEd25519", "value": "ww0z4WaZ0Xg+YI10w43wTWbBmM3dpVza4mmSQYsd0ck=" }, "voting_power": "10", "proposer_priority": "0" } ] } } } } ``` :::tip **Note:** When querying Ethereum transactions versus Cosmos transactions, the transaction hashes are different. When querying Ethereum transactions, users need to use event query. Here's an example with the CLI: ```bash theme={null} curl -X GET "http://localhost:26657/tx_search?query=ethereum_tx.ethereumTxHash%3D0x8d43464891fac6c113e809e14dff1a3e608eae124d629799e42ca0e36562d9d7&prove=false&page=1&per_page=30&order_by=asc" -H "accept: application/json" ``` ::: # Block Explorers Source: https://sidiorresearchlabs.mintlify.app/develop/block-explorers/index Explore transactions, blocks, and accounts on HyperPaxeer. # Block Explorers Blockchain explorers allow users to query the blockchain for data. Explorers are often compared to search engines for the blockchain. By using an explorer, users can search and track balances, transactions, contracts, and other broadcast data to the blockchain. HyperPaxeer offers two types block explorers: an EVM explorer and a Cosmos explorer. Each explorer queries data respective to their environment with the EVM explorers querying Ethereum-formatted data (blocks, transactions, accounts, smart contracts, etc) and the Cosmos explorers querying Cosmos-formatted data (Cosmos and IBC transactions, blocks, accounts, module data, etc). ## List of Block Explorers Below is a list of public block explorers that support HyperPaxeer Mainnet and Testnet: ### Mainnet | Service | Support | URL | Contract Verification | | ---------- | -------------- | --------------------------------------------------------------------- | -------------------------------- | | Mintscan | `cosmos` `evm` | [mintscan.io/Paxeer-Network](https://www.mintscan.io/Paxeer-Network) | Yes but requires form submission | | Escan | `cosmos` `evm` | [escan.live](https://escan.live) | Permissionless | | BigDipper | `cosmos` | [HyperPaxeer.bigdipper.live/](https://Paxeer-Network.bigdipper.live/) | No | | ATOMScan | `cosmos` | [atomscan.com/Paxeer-Network](https://atomscan.com/Paxeer-Network) | No | | NGExplorer | `cosmos` | [HyperPaxeer.explorers.guru](https://Paxeer-Network.explorers.guru) | No | ### Testnet | Service | Support | URL | | ---------- | -------------- | ------------------------------------------------------------------------------------------------ | | Escan | `cosmos` `evm` | [testnet.escan.live](https://testnet.escan.live) | | Mintscan | `cosmos` `evm` | [testnet.mintscan.io/Paxeer-Network-testnet](https://testnet.mintscan.io/Paxeer-Network-testnet) | | BigDipper | `cosmos` | [testnet.bigdipper.live](https://testnet.hyperpaxd.bigdipper.live/) | | Blockscout | `evm` | [evm.hyperpaxd.dev](https://evm.hyperpaxd.dev/) | | NGExplorer | `cosmos` | [testnet.hyperpaxd.explorers.guru](https://testnet.hyperpaxd.explorers.guru) | # Graph Indexers Source: https://sidiorresearchlabs.mintlify.app/develop/graphs-indexers/index Efficiently query blockchain data with graph indexing. # Graphs Indexers A graph indexer allows developers to efficiently query the network for information about transactions, addresses, and other data stored on the blockchain. This enables developers to build decentralized applications that can access and display the data in a meaningful way, without having to search through the entire blockchain for each query. For example, a graph indexer could be used to search for all transactions associated with a particular address or to find all transactions that include a specific token. This type of indexing can greatly improve the speed and efficiency of decentralized applications and make it easier for users to access and analyze the data stored on the blockchain. ## List of Graph Indexers ### Mainnet | Service | Description | Support | Links & Features | | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **[Satsuma](https://www.satsuma.xyz/)** | Subgraph Indexer | `evm` | | | **Covalent** | Provides a Unified API for accessing data from over 100 blockchain networks. Indexing service for all EVM transactions on HyperPaxeer | `evm` |
  • Get an [API Key](https://www.covalenthq.com/platform/#/auth/register/)
  • [Docs](https://www.covalenthq.com/docs/networks/Paxeer-Network/)
  • Cost: Free to use with 100,000 credits to use their API endpoints
| | **Numia** | Indexes both EVM and Cosmos transactions on HyperPaxeer. Also indexes other chains on the Cosmos ecosystem. The service runs on Google BigQuery and requires users to sign up for their own accounts. | `cosmos` `evm` |
  • [Get started with GCP instruction](https://docs.numia.xyz/using-numia/getting-started-with-gcp)
  • [Pulling Numia Data Image](https://docs.numia.xyz/using-numia/querying-numia-datasets)
  • [HyperPaxeer chain](https://docs.numia.xyz/using-numia/chains/Paxeer-Network)
  • [Google Cloud](https://cloud.google.com/) provides free trial with ample credits (\$300) to run many queries for at least a few months
| | **[SubQuery](https://subquery.network/)** | A fast, reliable, and decentralised indexer empowering developers to build customised APIs for their web3 projects. Supporting over 100+ networks, get started with our SDK, managed service & decentralised network. | `cosmos` + `evm` |
  • [Quick start](https://academy.subquery.network/quickstart/quickstart.html)
  • [Managed Services](https://managedservice.subquery.network/)
  • [Decentralised Network](https://subquery.network/network)
| | **[Envio](https://envio.dev/)** | Envio is a full-featured data indexing solution that provides application developers with a seamless and efficient way to index and aggregate real-time and historical blockchain data for any EVM. Designed to optimize the user experience, Envio offers automatic code generation, flexible language support, multi-chain data aggregation, and a reliable cost-effective hosted service. | `evm` |
  • [Quickstart](https://docs.envio.dev/docs/quickstart)
  • [Hosted Service](https://docs.envio.dev/docs/hosted-service)
  • [Contract Import](https://docs.envio.dev/docs/contract-import)
| | **[Flair](https://docs.flair.dev/)** | Fast parallelized EVM indexing to your own MongoDB, Postgres, DynamoDB. | `evm` |
  • [Quickstart](https://docs.flair.dev/#getting-started)
  • [Examples](https://github.com/flair-sdk/examples)
| # Develop Source: https://sidiorresearchlabs.mintlify.app/develop/index Build on HyperPaxeer. # Getting Started Looking to build a dApp on HyperPaxeer? Following this documentation and our academy you can learn how and become part of the rich ecosystem of EVM builders on Cosmos. Whether you are building new use cases on HyperPaxeer or porting an existing dApp from another chain, you'll want to check out the sections on 1. Building and deploying [EVM Smart Contracts](./develop/smart-contracts) 2. Integrating [wallets](./develop/wallet-integration) (e.g. Keplr and MetaMask) into your Frontend 3. Available developer [Tools](./tools/index.md) ## Why develop dApps on HyperPaxeer? The HyperPaxeer Core Development Team is on a mission to provide the foundational tools necessary for building the cross-chain applications of the future, freeing developers from the confines of today’s siloed blockchains. HyperPaxeer focuses on cross-chain **innovation** so that developers can build entirely new dApp experiences for their users. Deploying smart contracts on HyperPaxeer is **easy**, as the HyperPaxeer blockchain is fully compatible with Ethereum and its rich ecosystem of robust tooling, wallets, explorers, a surplus of assets, and intelligent end-users. At the same time, HyperPaxeer allows developers to build **scalable** EVM dApp chains with the upcoming HyperPaxeer SDK and it hosts one of the most active community governance that seeks **fairness** across all key actors (users, builders, and validators). HyperPaxeer does this by leveraging the interoperability of the Cosmos Ecosystem and the market-dominating support for EVM development. This allows dApp developers to use Ethereum smart contracts to implement the business logic on-chain while having access to Cosmos chain functionalities, such as exchanging value with the rest of the Cosmos Ecosystem through the Inter Blockchain Communication Protocol (IBC). ## Contributors You can also contribute to the HyperPaxeer ecosystem without building a dApp. Head over to [tools](./tools/index.md) to learn how to contribute as a full-stack developer by building new dev tools or [protocol](../protocol) to help out building the core protocol. # Mainnet Source: https://sidiorresearchlabs.mintlify.app/develop/mainnet # Mainnet Before real users transact with actual funds on your dApp, account for security, deployment, monitoring, and support requirements. HyperPaxeer currently operates mainnet only, so test contracts locally or on private development networks before production deployment. ## Deployment You can deploy your contracts on mainnet using the [JSON-RPC](../develop/smart-contracts#deploy-with-ethereum-json-rpc) and the [mainnet network endpoints](./../develop/api/networks). Before you do so, review the following considerations. ### Security Thoroughly test your smart contracts in local and private environments before deploying to HyperPaxeer mainnet. Comprehensive tests should cover all functions, error handling, and edge cases. Whenever possible, perform a comprehensive security audit of the smart contract code to identify and eliminate any potential vulnerabilities or weaknesses. This is especially vital for the mainnet, as the code will be accessible to everyone and any security flaws could result in substantial losses. Learn about the common vulnerabilities and contract security practices. External auditors can also help optimize your contract's performance. Ensure proper management of contract ownership and consider implementing a multi-sig mechanism for increased security. This will allow you to maintain deployment ownership within your team instead of one specific owner that might leave the team. Last but not least, verify that any external libraries or dependencies used by the contract are up-to-date and secure. ### Contract upgradeability Consider the possibility of upgrading the contract in the future and implement upgrade mechanisms if needed. This will enable you to make changes to the contract without having to redeploy it, creating a new contract. ### Costs Evaluate the gas costs associated with deploying and executing the smart contract, including the cost of deploying the contract and executing its functions are sufficient or efficient for end users. ### Contract documentation Provide clear and comprehensive documentation for the contract, including its purpose, functions, and potential risks. This will assist users in understanding how to use the contract and make it easier for other developers to review and contribute to the code. ## Token distribution You're dApp might issue an ERC-20 token, e.g. to give token holders additional benefits. In this case, you will need to decide on how to distribute them and what kind of narrative you want to create. ### Airdrop One option is to distribute tokens to users through an airdrop. For some inspiration on how to select eligible receivers of an airdrop have a look at the \[HyperPaxeer Rektdrop]\([https://medium.com/Paxeer-Network/the-Paxeer](https://medium.com/Paxeer-Network/the-Paxeer) Network-rektdrop-abbe931ba823). ### Token Registration HyperPaxeer allows for ERC-20 tokens to be used cross-chain. Once some of your tokens have been minted, you can register a token pair through governance, which will allow users to send your tokens across chains. Head over to our Academy to learn how to [register your ERC-20 token](https://academy.evmosd.org/articles/advanced/erc20-registration). ## Community Make yourself heard in the HyperPaxeer community and explain what value your dApp provides. An essential part of building a dApp is getting in touch with the community to showcase how they can take ownership or start contributing to your project. This will not only help your dApp's visibility but might result in a new community of users, that want to improve your dApp. Head over to the [HyperPaxeer Telegram](https://t.me/paxeernetwork) channel get in touch with the community and contributors and showcase your dApp on one of the next community calls. # Oracles Source: https://sidiorresearchlabs.mintlify.app/develop/oracles/index Connect smart contracts to off-chain data sources. # Oracles HyperPaxeer supports several oracle providers to enable smart contracts to access off-chain data and interact with the real world (e.g. price feeds or randomness). These oracles serve as a bridge between the decentralized, trustless environment of blockchain and the centralized, traditional internet. An oracle is a piece of software that retrieves data from external sources and feeds it into smart contracts on the blockchain. This enables smart contracts to respond to real-world events, trigger automated actions, and execute their intended functions. ## List of Oracles ### Mainnet | Service | Description | Links & Features | | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **[Pyth](https://docs.pyth.network/)** | Leverages over [70 first-party publishers](https://pyth.network/publishers) to publish financial market data to numerous blockchains. They provide data feeds to various assets classes, such as [US equities, commodities, and cryptocurrencies](https://pyth.network/price-feeds/). |
  • [Developer Docs](https://docs.pyth.network/)
  • [Pyth Client for Linux](https://github.com/pyth-network/pyth-client)
  • [Pyth TS client NPM](https://www.npmjs.com/package/@pythnetwork/client)
  • Find audit reports [here](https://github.com/pyth-network/audit-reports)
| | **[Adrastia](https://docs.adrastia.io/)** | Provides a decentralized and permissionless oracle network that is secure, reliable, and easy to use. It uses [three types of contracts](https://docs.adrastia.io/structure/contracts) to provide secure data feeds: Accumulators, Intermediate oracles & Aggregator oracles |
  • HyperPaxeer data and contract address can be found [here](https://docs.adrastia.io/deployments/Paxeer-Network)
| | **[DIA](https://docs.diadata.org/introduction/readme)** | Enables the sourcing, validation and sharing of transparent and verified data feeds for traditional and digital financial applications. DIA’s institutional-grade data feeds cover asset prices, metaverse data, lending rates and more. Data is directly sourced from a broad array of on-chain and off-chain sources at individual trade-level |
  • DIA feeds are fully customizable with regards to the mix of sources and methodologies, resulting in tailor-made, high resilience feeds
  • [HyperPaxeer](https://docs.diadata.org/documentation/oracle-documentation/deployed-contracts#HyperPaxeer) Mainnet and Testnet contracts available for use. Update frequency is 2 hrs.
  • [Link to DIA's API](https://docs.diadata.org/products/token-price-feeds/access-api-endpoints/api-endpoints)
  • DIA has a [custom feed builder](https://app.diadata.org/feed-builder) and the supported token pairs are located [here](https://docs.diadata.org/documentation/oracle-documentation/deployed-contracts#HyperPaxeer)
  • the [DIA team Discord](https://go.diadata.org/dev-discord)
| | **[Redstone](https://docs.redstone.finance/docs/introduction)** | Offers a radically different design of Oracles catering for the needs of modern Defi protocols |
  • Data providers can avoid the requirement of continuous on-chain data delivery
  • Allow end users to self-deliver signed Oracle data on-chain
  • Use the decentralized Streamr network to deliver signed oracle data to the end users
  • Use token incentives to motivate data providers to maintain data integrity and uninterrupted service
  • Leverage the Arweave blockchain as a cheap and permanent storage for archiving Oracle data and maintaining data providers' accountability
  • Examples of Redstone EVM Connector can be found [here](https://github.com/redstone-finance/redstone-evm-connector-examples/blob/main/contracts/example-custom-urls.sol)
| | **[SEDA Network](https://docs.seda.xyz/seda-network/introduction/the-oracle-problem)** | A multi-chain-native data transmission protocol built on an entirely decentralized foundation. The SEDA network is a Proof-of-Stake on-chain data provision solution that allows anyone to provide and access high-quality data on all blockchain networks |
  • [SEDA Chain](https://github.com/sedaprotocol/seda-chain)
| ## How do Oracles work? ```sql theme={null} +------------+ +------------+ +-------------+ | External | | Oracle | | Smart | | Data Source| | Service | | Contract | +------------+ +------------+ +-------------+ | | | | API Call | | |---------------------> | | | | Retrieve External | | | Data via API Call | | |---------------------->| | | | | | Use External Data | | | in Smart Contract | | |<----------------------| | | | | | Return Result to | | | Smart Contract | | |<----------------------| | | | ``` In this diagram: * External Data Source refers to a source of data outside the blockchain network, such as a stock market, weather service, or other external API. * Oracle Service is a third-party service that acts as a bridge between the external data source and the smart contract. It retrieves the data from the external source and provides it to the smart contract. * Smart Contract is a self-executing contract that is deployed on the blockchain network. It uses the data provided by the oracle to perform certain actions, such as releasing funds or triggering events. * API Call refers to the request made by the smart contract to the oracle service, asking for the required external data. * Retrieve External Data refers to the process of retrieving the requested data from the external data source via the API call. * Use External Data refers to the process of using the retrieved data in the smart contract to perform actions, such as condition checking and state changes. * Return Result refers to the process of returning the result of the action performed in the smart contract back to the oracle. # Custom improvement proposals Source: https://sidiorresearchlabs.mintlify.app/develop/smart-contracts/custom-improvement-proposals # Custom Improvement Proposals With the release [v19.0.0](https://github.com/Paxeer-Network/Paxeer-Network/releases/tag/v19.0.0) a new feature called custom improvement proposals has been introduced in the HyperPaxeer framework. Custom improvement proposals allow protocol developers to modify the behavior of the EVM opcodes to tailor their functionalities to the specific needs. ## Operations Operations are the base components of the Ethereum Virtual Machine (EVM) which allow the execution of the smart contract logic. When a developer builds a smart contract, the code written in Solidity, or Vyper, is not directly interpretable by the EVM. Before being able to execute the code in the blockchain, the contract has to be compiled via one of the available compilers, like [solc](https://docs.soliditylang.org/en/latest/using-the-compiler.html). The compilation converts the human-readable contract code into a sequence of operations that the virtual machine can interpret and execute to perform state transitions or query the latest committed state. These operations are called **opcodes**, and are contained in a structure called [**jump table**](https://github.com/Paxeer-Network/Paxeer-Network/blob/v19.0.0/x/evm/core/vm/jump_table.go#L120-L1094). Each opcode is defined by specifying the logic that has to be executed when it is called inside the EVM, its relationship with the memory, and the gas cost associated with it. More specifically, an opcode is completely defined by: * `SetExecute`: update the execution logic for the opcode. * `SetConstantGas`: update the value used for the constant gas cost. * `SetDynamicGas`: update the function used to compute the dynamic gas cost. * `SetMinStack`: update the minimum number of items in the stack required to execute the operation. * `SetMaxStack`: update the maximum number of items that will be in the stack after executing the operation. * `SetMemorySize`: the memory size required by the operation. Within the HyperPaxeer framework, developers can modify any of the previous properties. ## Improvement Proposals Improvement proposals are the approach used by HyperPaxeer and Ethereum to modify the behavior of opcodes. They are composed of a function, which has access to the jump table to apply specific changes to operation behavior, and a name. In the context of Ethereum, these protocol changes are named Ethereum Improvement Proposals (EIPs) and are identified by a unique ID. For example, [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) is used to introduce the base fee. To allow any HyperPaxeer partner to define their own specific improvements without overlapping with HyperPaxeer and Ethereum ones, each proposal is identified by a string, that is composed of the chain name and a number. For example, default HyperPaxeer improvements are associated with the string `HyperPaxeer_XXXX`. This allows each chain to define their improvements without having to worry about existing or future ID clashes between different chains. Additionally, the ability to start enumeration at 0 is better for chain developers and allows having a better overview of the historical progress for each chain. Below, you will find an example of how the HyperPaxeer chain uses this functionality to modify the behavior of the `CREATE` and `CREATE2` opcodes. First, the modifier function has to be defined: ```go theme={null} // Enable0000 contains the logic to modify the CREATE and CREATE2 opcodes // constant gas value. func Enable0000(jt *vm.JumpTable) { multiplier := 10 currentValCreate := jt[vm.CREATE].GetConstantGas() jt[vm.CREATE].SetConstantGas(currentValCreate * multiplier) currentValCreate2 := jt[vm.CREATE2].GetConstantGas() jt[vm.CREATE2].SetConstantGas(currentValCreate2 * multiplier) } ``` Then, the function as to be associated with a name via a custom activator: ```go theme={null} HyperPaxeerActivators = map[string]func(*vm.JumpTable){ "HyperPaxeer_0": eips.Enable0000, } ``` ## Activation of Improvement Proposals Due to continuous changes in the users' interaction with the protocol, and to introduce a safety measure along with the freedom to customize the virtual machine behavior, custom improvement proposals are not active by default. The activation of selected improvement proposals is controlled by the [EVM module's parameters](https://github.com/Paxeer-Network/Paxeer-Network/blob/main/proto/ethermint/evm/v1/evm.proto#L17-L18). There are two ways of introducing the required parameter changes: 1. **Upgrade**: create a protocol upgrade handler which introduces the proposal name in the active list. 2. **Governance**: create governance proposal to add an improvement proposal to the EVM module parameters. This approach gives developers the ability to react to security issues or market conditions, while keeping the chain's participants in the loop. ## Additional Resources 1. [HyperPaxeer Custom EIPs](https://github.com/Paxeer-Network/Paxeer-Network/blob/main/app/eips/README.md): please refer to this document for a detailed description of how opcodes and custom improvement proposals have to be used in the HyperPaxeer framework. # Authorization Source: https://sidiorresearchlabs.mintlify.app/develop/smart-contracts/evm-extensions/authorization # Authorization The user should grant authorization to allow smart contracts to send messages on behalf of a user account. This is achieved by the `Authorization.sol` that provides the necessary functions to grant approvals and allowances. The precompiled contracts use the `AuthorizationI` interface, to allow users to approve the corresponding messages and amounts. ## Solidity Interfaces ### `Authorization.sol` Find the [Solidity interface in the HyperPaxeer/extensions repo](https://github.com/Paxeer-Network/extensions/blob/main/precompiles/common/Authorization.sol). ## Transactions * `approve` Approves a list of Cosmos or IBC transactions with a specific amount of tokens ```solidity theme={null} function approve( address spender, uint256 amount, string[] calldata methods ) external returns (bool approved); ``` * `revoke` Revokes authorizations of Cosmos transactions. ```solidity theme={null} function revoke( address spender, string[] calldata methods ) external returns (bool revoked); ``` * `increaseAllowance` Increase the allowance of a given spender by a specific amount of tokens for IBC transfer methods or staking ```solidity theme={null} function increaseAllowance( address spender, uint256 amount, string[] calldata methods ) external returns (bool approved); ``` * `decreaseAllowance` Decreases the allowance of a given spender by a specific amount of tokens for IBC transfer methods or staking ```solidity theme={null} function decreaseAllowance( address spender, uint256 amount, string[] calldata methods ) external returns (bool approved); ``` ## Queries * `allowance` Returns the remaining number of tokens that the spender will be allowed to spend on behalf of the owner through IBC transfer methods or staking. This is zero by default ```solidity theme={null} function allowance( address owner, address spender, string calldata method ) external view returns (uint256 remaining); ``` ## Events * `Approval` This event is emitted when the allowance of a spender is set by a call to the `approve` method. The `value` field specifies the new allowance and the `methods` field holds the information for which methods the approval was set. ```solidity theme={null} event Approval( address indexed owner, address indexed spender, string[] methods, uint256 value ); ``` * `Revocation` This event is emitted when an owner revokes a spender's allowance. ```solidity theme={null} event Revocation( address indexed owner, address indexed spender, string[] methods ); ``` * `AllowanceChange` This event is emitted when the allowance of a spender is changed by a call to the decrease or increase allowance method. The `values` field specifies the new allowances and the `methods` field holds the information for which methods the approval was set. ```solidity theme={null} event AllowanceChange( address indexed owner, address indexed spender, string[] methods, uint256[] values ); ``` # Distribution Source: https://sidiorresearchlabs.mintlify.app/develop/smart-contracts/evm-extensions/distribution # Distribution ## Solidity Interface & ABI `Distribution.sol` is an interface through which Solidity contracts can interact with Cosmos SDK distribution. This is convenient for developers as they don’t need to know the implementation details behind the `x/distribution` module in the Cosmos SDK. Instead, they can interact with distribution functions using the Ethereum interface they are familiar with. ### Interface `Distribution.sol` Find the [Solidity interface in the HyperPaxeer/extensions repo](https://github.com/Paxeer-Network/extensions/blob/main/precompiles/stateful/Distribution.sol). ### ABI Find the [ABI in the HyperPaxeer/extensions repo](https://github.com/Paxeer-Network/extensions/blob/main/precompiles/abi/distribution.json). ## Transactions * `setWithdrawAddress` ```solidity theme={null} /// @dev Change the address, that can withdraw the rewards of a delegator. /// Note that this address cannot be a module account. /// @param delegatorAddress The address of the delegator /// @param withdrawerAddress The address that will be capable of withdrawing rewards for /// the given delegator address function setWithdrawAddress( address delegatorAddress, string memory withdrawerAddress ) external returns (bool success); ``` * `withdrawDelegatorRewards` ```solidity theme={null} /// @dev Withdraw the rewards of a delegator from a validator /// @param delegatorAddress The address of the delegator /// @param validatorAddress The address of the validator /// @return amount The amount of Coin withdrawn function withdrawDelegatorRewards( address delegatorAddress, string memory validatorAddress ) external returns ( Coin[] calldata amount ); ``` * `withdrawValidatorCommission` ```solidity theme={null} /// @dev Withdraws the rewards commission of a validator. /// @param validatorAddress The address of the validator /// @return amount The amount of Coin withdrawn function withdrawValidatorCommission( string memory validatorAddress ) external returns ( Coin[] calldata amount ); ``` ## Queries * `validatorDistribution` ```solidity theme={null} /// @dev Queries validator commission and self-delegation rewards for validator. /// @param validatorAddress The address of the validator /// @return distributionInfo The validator's distribution info function validatorDistributionInfo( string memory validatorAddress ) external view returns ( ValidatorDistributionInfo calldata distributionInfo ); ``` * `validatorOutstandingRewards` ```solidity theme={null} /// @dev Queries the outstanding rewards of a validator address. /// @param validatorAddress The address of the validator /// @return rewards The validator's outstanding rewards function validatorOutstandingRewards( string memory validatorAddress ) external view returns ( DecCoin[] calldata rewards ); ``` * `validatorCommission` ```solidity theme={null} /// @dev Queries the accumulated commission for a validator. /// @param validatorAddress The address of the validator /// @return commission The validator's commission function validatorCommission( string memory validatorAddress ) external view returns ( DecCoin[] calldata commission ); ``` * `validatorSlashes` ```solidity theme={null} /// @dev Queries the slashing events for a validator in a given height interval /// defined by the starting and ending height. /// @param validatorAddress The address of the validator /// @param startingHeight The starting height /// @param endingHeight The ending height /// @return slashes The validator's slash events /// @return pageResponse The pagination response for the query function validatorSlashes( string memory validatorAddress, uint64 startingHeight, uint64 endingHeight ) external view returns ( ValidatorSlashEvent[] calldata slashes, PageResponse calldata pageResponse ); ``` * `delegationRewards` ```solidity theme={null} /// @dev Queries the total rewards accrued by a delegation from a specific address to a given validator. /// @param delegatorAddress The address of the delegator /// @param validatorAddress The address of the validator /// @return rewards The total rewards accrued by a delegation. function delegationRewards( address delegatorAddress, string memory validatorAddress ) external view returns ( DecCoin[] calldata rewards ); ``` * `delegationTotalRewards` ```solidity theme={null} /// @dev Queries the total rewards accrued by each validator, that a given /// address has delegated to. /// @param delegatorAddress The address of the delegator /// @return rewards The total rewards accrued by each validator for a delegator. /// @return total The total rewards accrued by a delegator. function delegationTotalRewards( address delegatorAddress ) external view returns ( DelegationDelegatorReward[] calldata rewards, DecCoin[] calldata total ); ``` * `delegatorValidators` ```solidity theme={null} /// @dev Queries all validators, that a given address has delegated to. /// @param delegatorAddress The address of the delegator /// @return validators The addresses of all validators, that were delegated to by the given address. function delegatorValidators( address delegatorAddress ) external view returns (string[] calldata validators); ``` * `delegatorWithdrawAddress` `delegatorWithdrawAddress` queries withdraw address of a delegator ```solidity theme={null} /// @dev Queries the address capable of withdrawing rewards for a given delegator. /// @param delegatorAddress The address of the delegator /// @return withdrawAddress The address capable of withdrawing rewards for the delegator. function delegatorWithdrawAddress( address delegatorAddress ) external view returns (string memory withdrawAddress); ``` ## Events Each of the transactions emits its corresponding event. These are: * `SetWithdrawerAddress` ```solidity theme={null} /// @dev SetWithdrawerAddress defines an Event emitted when a new withdrawer address is being set /// @param caller the caller of the transaction /// @param withdrawerAddress the newly set withdrawer address event SetWithdrawerAddress( address indexed caller, string withdrawerAddress ); ``` * `WithdrawDelegatorRewards` ```solidity theme={null} /// @dev WithdrawDelegatorRewards defines an Event emitted when rewards from a delegation are withdrawn /// @param delegatorAddress the address of the delegator /// @param validatorAddress the address of the validator /// @param amount the amount being withdrawn from the delegation event WithdrawDelegatorRewards( address indexed delegatorAddress, string indexed validatorAddress, uint256 amount ); ``` * `WithdrawValidatorCommission` ```solidity theme={null} /// @dev WithdrawValidatorCommission defines an Event emitted when validator commissions are being withdrawn /// @param validatorAddress is the address of the validator /// @param commission is the total commission earned by the validator event WithdrawValidatorCommission( string indexed validatorAddress, uint256 commission ); ``` ## Interact with the Solidity Interface Below are some examples of how to interact with this Solidity interface from your smart contracts. Make sure to import the precompiled interface, e.g.: ```solidity theme={null} import "https://github.com/Paxeer-Network/extensions/blob/main/precompiles/stateful/Distribution.sol"; ``` ### Set withdraw address The `changeWithdrawAddress` function allows a user to set a new withdraw address in the Cosmos `x/distribution` module. For this transaction to be successful, make sure the user had already approved the `MSG_SET_WITHDRAWER_ADDRESS` message. ```solidity theme={null} function changeWithdrawAddress( string memory _withdrawAddr ) public returns (bool) { return distribution.DISTRIBUTION_CONTRACT.setWithdrawAddress( msg.sender, _withdrawAddr ); } ``` ### Withdraw staking rewards The `withdrawStakingRewards` function allows a user to withdraw his/her rewards corresponding to a specified validator. For this transaction to be successful, make sure the user had already approved the `MSG_WITHDRAW_DELEGATOR_REWARD` message. ```solidity theme={null} function withdrawStakingRewards( string memory _valAddr ) public returns (types.Coin[] memory) { return distribution.DISTRIBUTION_CONTRACT.withdrawDelegatorRewards( msg.sender, _valAddr ); } ``` ### Withdraw validator commission If the user is running a validator, he/she could withdraw the corresponding commission using a smart contract. The user could use a function similar to `withdrawCommission`. For this transaction to be successful, make sure the user had already approved the `MSG_WITHDRAW_VALIDATOR_COMMISSION` message. ```solidity theme={null} function withdrawCommission( string memory _valAddr ) public returns (types.Coin[] memory) { return distribution.DISTRIBUTION_CONTRACT.withdrawValidatorCommission( _valAddr ); } ``` ### Queries Similarly to transactions, smart contracts can use query methods. These are read-only methods. Examples of this are the `getDelegationRewards` and `getValidatorCommision` functions that return the information for the specified validator address. ```solidity theme={null} getDelegationRewards( string memory _valAddr ) public view returns (types.DecCoin[] memory) { return distribution.DISTRIBUTION_CONTRACT.delegationRewards( msg.sender, _valAddr ); } function getValidatorCommission( string memory _valAddr ) public view returns (types.DecCoin[] memory) { return distribution.DISTRIBUTION_CONTRACT.validatorCommission(_valAddr); } ``` # Evm extensions Source: https://sidiorresearchlabs.mintlify.app/develop/smart-contracts/evm-extensions/evm-extensions # EVM Extensions Stateful EVM Extensions on the core protocol allow dApps and users to access logic outside of the EVM. Acting as a gateway, these EVM Extensions define how smart contracts can perform cross-chain transactions (via IBC) and interact with core functionalities on the HyperPaxeer chain (e.g. staking, voting) from the EVM. :::tip **Note**: Not sure what EVM extensions are? EVM extensions behave like smart contracts that are compiled and deployed within the EVM. If you are familiar with the EVM, you may know them as Precompiles. These have predefined addresses and, according to their logic, can be classified as stateful or stateless. When they change the state of the chain (transactions) or access state data (queries), extensions are considered "stateful"; when they don't, they're "stateless". ::: ## EVM Extensions documentation Find in this section an outline of the currently implemented EVM extensions with transactions, queries, and examples of using them: * [Authorization interface (read first if you're new to EVM extensions)](./authorization.md) * [EVM Extensions shared types](./types.md) * [`x/staking` module EVM extension](./staking.md) * [`x/distribution` module EVM extension](./distribution.md) * [`ibc/transfer` module EVM extension](./ibc-transfer.md) * [`x/vesting` module EVM extension](./vesting.md) :::tip **Note**: Find the EVM Extensions Solidity interfaces and examples in the [HyperPaxeer Extensions repo](https://github.com/Paxeer-Network/extensions). ::: ## Other Learning Resources * [EVM Extensions - Staking & Distribution](https://academy.evmosd.org/articles/advanced/evm-extensions-stk-distr) academy article * [Diving into EVM Extensions Workshop (DoraHacks Hackathon)](https://www.youtube.com/live/pJhOfZ0ScAE?feature=share) # Ibc transfer Source: https://sidiorresearchlabs.mintlify.app/develop/smart-contracts/evm-extensions/ibc-transfer # IBC Transfer ## Solidity Interface & ABI `ICS20.sol` - previously known as `IBCTransfer.sol` - is an interface through which Solidity contracts can interact with the IBC protocol on HyperPaxeer chain. This is convenient for developers as they don’t need to know the implementation details behind the `transfer` module in [IBC-go](https://ibc.cosmos.network/). Instead, they can perform IBC transfers using the Ethereum interface they are familiar with. An example of a simple implementation can be found in the [HyperPaxeer/extensions repo](https://github.com/Paxeer-Network/extensions/tree/main/examples/simple-ibc-transfer). ### Interface `ICS20.sol` Find the [Solidity interface in the HyperPaxeer/extensions repo](https://github.com/Paxeer-Network/extensions/blob/main/precompiles/stateful/ICS20.sol). ### ABI Find the [ABI in the HyperPaxeer/extensions repo](https://github.com/Paxeer-Network/extensions/blob/main/precompiles/abi/ics20.json). ## Transactions * `approve` ```solidity theme={null} /// @dev Approves IBC transfer with a specific amount of tokens. /// @param spender spender The address which will spend the funds. /// @param allocations The allocations for the authorization. function approve( address spender, Allocation[] calldata allocations ) external returns (bool approved); ``` * `revoke` ```solidity theme={null} /// @dev Revokes IBC transfer authorization for a specific spender /// @param spender The address which will spend the funds. function revoke(address spender) external returns (bool revoked); ``` * `increaseAllowance` ```solidity theme={null} /// @dev Increase the allowance of a given spender by a specific amount of tokens and IBC connection for IBC transfer methods. /// @param spender The address which will spend the funds. /// @param sourcePort The source port of the IBC transaction. /// @param sourceChannel The source channel of the IBC transaction. /// @param denom The denomination of the tokens transferred. /// @param amount The amount of tokens to be spent. function increaseAllowance( address spender, string calldata sourcePort, string calldata sourceChannel, string calldata denom, uint256 amount ) external returns (bool approved); ``` * `decreaseAllowance` ```solidity theme={null} /// @dev Decreases the allowance of a given spender by a specific amount of tokens for for IBC transfer methods. /// @param spender The address which will spend the funds. /// @param sourcePort The source port of the IBC transaction. /// @param sourceChannel The source channel of the IBC transaction. /// @param denom The denomination of the tokens transferred. /// @param amount The amount of tokens to be spent. function decreaseAllowance( address spender, string calldata sourcePort, string calldata sourceChannel, string calldata denom, uint256 amount ) external returns (bool approved); ``` * `transfer` ```solidity theme={null} /// @dev Transfer defines a method for performing an IBC transfer. /// @param sourcePort the address of the validator /// @param sourceChannel the address of the validator /// @param denom the denomination of the Coin to be transferred to the receiver /// @param amount the amount of the Coin to be transferred to the receiver /// @param sender the hex address of the sender /// @param receiver the bech32 address of the receiver /// @param timeoutHeight the bech32 address of the receiver /// @param timeoutTimestamp the bech32 address of the receiver /// @param memo the bech32 address of the receiver function transfer( string memory sourcePort, string memory sourceChannel, string memory denom, uint256 amount, address sender, string memory receiver, Height memory timeoutHeight, uint64 timeoutTimestamp, string memory memo ) external returns (uint64 nextSequence); ``` ## Queries * `denomTrace` ```solidity theme={null} /// @dev DenomTrace defines a method for returning a denom trace. function denomTrace( string memory hash ) external returns (DenomTrace memory denomTrace); ``` * `denomTraces` ```solidity theme={null} /// @dev DenomTraces defines a method for returning all denom traces. function denomTraces( PageRequest memory pageRequest ) external returns ( DenomTrace[] memory denomTraces, PageResponse memory pageResponse ); ``` * `denomHash` ```solidity theme={null} /// @dev DenomHash defines a method for returning a hash of the denomination trace info. function denomHash( string memory trace ) external returns (string memory hash); ``` * `allowance` ```solidity theme={null} /// @dev Returns the remaining number of tokens that spender will be allowed to spend on behalf of owner through /// IBC transfers. This is an empty array by default. /// @param owner The address of the account owning tokens. /// @param spender The address of the account able to transfer the tokens. /// @return allocations The remaining amounts allowed to spend for /// corresponding source port and channel. function allowance( address owner, address spender ) external view returns (Allocation[] memory allocations); ``` ## Events Each of the transactions emits its corresponding event. These are: * `IBCTransfer` ```solidity theme={null} /// @dev Emitted when an ICS-20 transfer is executed. /// @param sender The address of the sender. /// @param receiver The address of the receiver. /// @param sourcePort The source port of the IBC transaction. /// @param sourceChannel The source channel of the IBC transaction. /// @param denom The denomination of the tokens transferred. /// @param amount The amount of tokens transferred. /// @param memo The IBC transaction memo. event IBCTransfer( address indexed sender, string indexed receiver, string sourcePort, string sourceChannel, string denom, uint256 amount, string memo ); ``` * `IBCTransferAuthorization` ```solidity theme={null} /// @dev Emitted when an ICS-20 transfer authorization is granted. /// @param grantee The address of the grantee. /// @param granter The address of the granter. /// @param sourcePort The source port of the IBC transaction. /// @param sourceChannel The source channel of the IBC transaction. /// @param spendLimit The coins approved in the allocation event IBCTransferAuthorization( address indexed grantee, address indexed granter, string sourcePort, string sourceChannel, Coin[] spendLimit ); ``` * `RevokeIBCTransferAuthorization` ```solidity theme={null} /// @dev This event is emitted when an owner revokes a spender's allowance. /// @param owner The owner of the tokens. /// @param spender The address which will spend the funds. event RevokeIBCTransferAuthorization( address indexed owner, address indexed spender ); ``` * `AllowanceChange` ```solidity theme={null} /// @dev This event is emitted when the allowance of a spender is changed by a call to the decrease or increase /// allowance method. The values field specifies the new allowances and the methods field holds the /// information for which methods the approval was set. /// @param owner The owner of the tokens. /// @param spender The address which will spend the funds. /// @param methods The message type URLs of the methods for which the approval is set. /// @param values The amounts of tokens approved to be spent. event AllowanceChange( address indexed owner, address indexed spender, string[] methods, uint256[] values ); ``` # Staking Source: https://sidiorresearchlabs.mintlify.app/develop/smart-contracts/evm-extensions/staking # Staking ## Solidity Interface & ABI `Staking.sol` is an interface through which Solidity contracts can interact with Cosmos SDK staking. This is convenient for developers as they don’t need to know the implementation details behind the `x/staking` module in the Cosmos SDK. Instead, they can interact with staking functions using the Ethereum interface they are familiar with. ### Interface `Staking.sol` Find the [Solidity interface in the HyperPaxeer/extensions repo](https://github.com/Paxeer-Network/extensions/blob/main/precompiles/stateful/Staking.sol). ### ABI Find the [ABI in the HyperPaxeer/extensions repo](https://github.com/Paxeer-Network/extensions/blob/main/precompiles/abi/staking.json). ## Transactions The Staking solidity interface includes the following transactions * `delegate` `delegate` defines a method for performing a delegation of coins from a delegator to a validator. ```solidity theme={null} function delegate( address delegatorAddress, string memory validatorAddress, uint256 amount ) external returns (bool success); ``` * `undelegate` `undelegate` defines a method for performing an undelegation from a delegate and a validator. ```solidity theme={null} function undelegate( address delegatorAddress, string memory validatorAddress, uint256 amount ) external returns (int64 completionTime); ``` * `redelegate` Redelegate defines a method for performing a redelegation of coins from a delegator and source validator to a destination validator ```solidity theme={null} function redelegate( address delegatorAddress, string memory validatorSrcAddress, string memory validatorDstAddress, uint256 amount ) external returns (int64 completionTime); ``` * `cancelUnbondingDelegation` `cancelUnbondingDelegation` allows delegators to cancel the unbondingDelegation entry and to delegate back to a previous validator. ```solidity theme={null} function cancelUnbondingDelegation( address delegatorAddress, string memory validatorAddress, uint256 amount, uint256 creationHeight ) external returns (bool success); ``` ## Queries * `delegation` get the given amount of the bond denomination to a validator. ```solidity theme={null} function delegation( address delegatorAddress, string memory validatorAddress ) external view returns (uint256 shares, Coin calldata balance); ``` * `unbondingDelegation` `unbondingDelegation` returns the unbonding delegation ```solidity theme={null} function unbondingDelegation( address delegatorAddress, string memory validatorAddress ) external view returns (UnbondingDelegationEntry[] calldata entries); ``` * `validator` `validator` queries validator info for given validator address ```solidity theme={null} function validator( string memory validatorAddress ) external view returns ( Validator calldata validator ); ``` * `validators` `validators` queries all validators that match the given status ```solidity theme={null} function validators( string memory status, PageRequest calldata pageRequest ) external view returns ( Validator[] calldata validators, PageResponse calldata pageResponse ); ``` * `redelegation` `redelegation` queries all redelegations from a source to a destination validator for a given delegator ```solidity theme={null} function redelegation( address delegatorAddress, string memory srcValidatorAddress, string memory dstValidatorAddress ) external view returns (RedelegationEntry[] calldata entries); ``` * `redelegations` `redelegations` queries all redelgations based on the specified criteria: for a given delegator and/or origin validator address and/or destination validator address in a specified pagination manner. ```solidity theme={null} function redelegations( address delegatorAddress, string memory srcValidatorAddress, string memory dstValidatorAddress, PageRequest calldata pageRequest ) external view returns ( RedelegationResponse[] calldata response, PageResponse calldata pageResponse ); ``` ## Events Each of the transactions emits its corresponding event. These are: * `Delegate` Delegate defines an Event emitted when a given amount of tokens are delegated from the delegator address to the validator address ```solidity theme={null} event Delegate( address indexed delegatorAddress, string indexed validatorAddress, uint256 amount, uint256 newShares ); ``` * `Unbond` Unbond defines an Event emitted when a given amount of tokens are unbonded from the validator address to the delegator address ```solidity theme={null} event Unbond( address indexed delegatorAddress, string indexed validatorAddress, uint256 amount, uint256 completionTime ); ``` * `Redelegate` Redelegate defines an Event emitted when a given amount of tokens are redelegated from the source validator address to the destination validator address ```solidity theme={null} event Redelegate( address indexed delegatorAddress, string indexed validatorSrcAddress, string indexed validatorDstAddress, uint256 amount, uint256 completionTime ); ``` * `CancelUnbondingDelegation` CancelUnbondingDelegation defines an Event emitted when a given amount of tokens that are in the process of unbonding from the validator address are bonded again ```solidity theme={null} event CancelUnbondingDelegation( address indexed delegatorAddress, string indexed validatorAddress, uint256 amount, uint256 creationHeight ); ``` ## Interact with the Solidity Interface Below are some examples of how to interact with this Solidity interface from your smart contracts. Make sure to import the precompiled interface, e.g.: ```solidity theme={null} import "https://github.com/Paxeer-Network/extensions/blob/main/precompiles/stateful/Staking.sol"; ``` ### Grant approval for the desired messages See below a function that grants approval to the smart contract to send all `x/staking` module messages on behalf of the sender account. In this case, the allowance amount is the maximum amount possible. You can tweak this function to approve only the desired messages and amounts. ```solidity theme={null} string[] private stakingMethods = [ MSG_DELEGATE, MSG_UNDELEGATE, MSG_REDELEGATE, MSG_CANCEL_UNDELEGATION ]; /// @dev Approves this smart contract to perform all staking transactions with the maximum amount of tokens on behalf of the transaction signer. /// @dev This creates a Cosmos Authorization Grant for the given methods. /// @dev This emits an Approval event. function approveAllStakingMethodsWithMaxAmount() public { bool success = STAKING_CONTRACT.approve( address(this), type(uint256).max, stakingMethods ); require(success, "Failed to approve staking methods"); } ``` ### Delegate to a validator The `stakeTokens` function allows the transaction sender to delegate the specified amount to his/her favorite validator. Keep in mind that, for this transaction to be successful, the user should have approved the `MSG_DELEGATE` previously (see the `approveAllStakingMethodsWithMaxAmount` defined in the code snippet above as an example). This function returns the completion time of the staking transaction and emits a `Delegate` event. ```solidity theme={null} /// @dev stake a given amount of tokens. Returns the completion time of the staking transaction. /// @dev This emits an Delegate event. /// @param _validatorAddr The address of the validator. /// @param _amount The amount of tokens to stake in ahpx. /// @return success Boolean to inform if the operation was successful or not. function stakeTokens( string memory _validatorAddr, uint256 _amount ) public returns (bool success) { return STAKING_CONTRACT.delegate(msg.sender, _validatorAddr, _amount); } ``` ### Undelegate from a validator The `unstakeTokens` function allows a user to unstake a given amount of tokens. It returns the completion time of the unstaking transaction and emits an `Undelegate` event. ```solidity theme={null} /// @dev unstake a given amount of tokens. Returns the completion time of the unstaking transaction. /// @dev This emits an Undelegate event. /// @param _validatorAddr The address of the validator. /// @param _amount The amount of tokens to unstake in ahpx. /// @return completionTime The completion time of the unstaking transaction. function unstakeTokens( string memory _validatorAddr, uint256 _amount ) public returns (int64 completionTime) { return STAKING_CONTRACT.undelegate(msg.sender, _validatorAddr, _amount); } ``` ### Redelegate to another validator With the `redelegateTokens` function, a user can redelegate a given amount of tokens. It returns the completion time of the redelegate transaction and emits a `Redelegate` event. ```solidity theme={null} /// @dev redelegate a given amount of tokens. Returns the completion time of the redelegate transaction. /// @dev This emits a Redelegate event. /// @param _validatorSrcAddr The address of the source validator. /// @param _validatorDstAddr The address of the destination validator. /// @param _amount The amount of tokens to redelegate in ahpx. /// @return completionTime The completion time of the redelegate transaction. function redelegateTokens( string memory _validatorSrcAddr, string memory _validatorDstAddr, uint256 _amount ) public returns (int64 completionTime) { return STAKING_CONTRACT.redelegate( msg.sender, _validatorSrcAddr, _validatorDstAddr, _amount ); } ``` ### Cancel unbonding from a validator With the `cancelUnbondingDelegation` function, a user can cancel an unbonding delegation. This function returns the completion time of the unbonding delegation cancellation transaction and emits a `CancelUnbondingDelegation` event. ```solidity theme={null} /// @dev cancel an unbonding delegation. Returns the completion time of the unbonding delegation cancellation transaction. /// @dev This emits an CancelUnbondingDelegation event. /// @param _validatorAddr The address of the validator. /// @param _amount The amount of tokens to cancel the unbonding delegation in ahpx. /// @param _creationHeight The creation height of the unbonding delegation. function cancelUnbondingDelegation( string memory _validatorAddr, uint256 _amount, uint256 _creationHeight ) public returns (bool success) { return STAKING_CONTRACT.cancelUnbondingDelegation( msg.sender, _validatorAddr, _amount, _creationHeight ); } ``` ### Queries Similarly to transactions, smart contracts can use query methods. To use these methods, there is no need for authorization, as these are read-only methods. Examples of this are these `getDelegation` and `getUnbondingDelegation` functions that return the information for the specified validator address. ```solidity theme={null} /// @dev Returns the delegation information for a given validator for the msg sender. /// @param _validatorAddr The address of the validator. /// @return shares and balance. The delegation information for a given validator for the msg sender. function getDelegation( string memory _validatorAddr ) public view returns (uint256 shares, Coin memory balance) { return STAKING_CONTRACT.delegation(msg.sender, _validatorAddr); } /// @dev Returns the unbonding delegation information for a given validator for the msg sender. /// @param _validatorAddr The address of the validator. /// @return entries The unbonding delegation entries for a given validator for the msg sender. function getUnbondingDelegation( string memory _validatorAddr ) public view returns (UnbondingDelegationEntry[] memory entries) { return STAKING_CONTRACT.unbondingDelegation(msg.sender, _validatorAddr); } ``` # Vesting Source: https://sidiorresearchlabs.mintlify.app/develop/smart-contracts/evm-extensions/vesting # Vesting ## Solidity Interface & ABI `Vesting.sol` is an interface through which Solidity contracts can interact with HyperPaxeer vesting module. This is convenient for developers as they don’t need to know the implementation details behind the `x/vesting` module in HyperPaxeer. Instead, they can interact with vesting accounts using the Ethereum interface they are familiar with. :::tip To learn more about the `x/vesting` module, check out the [module's docs](https://docs.paxeer.app/protocol/modules/vesting). ::: ### Interface `Vesting.sol` Find the [Solidity interface in the HyperPaxeer/extensions repo](https://github.com/Paxeer-Network/extensions/blob/main/precompiles/stateful/Vesting.sol). ### ABI Find the [ABI in the HyperPaxeer/extensions repo](https://github.com/Paxeer-Network/extensions/blob/main/precompiles/abi/vesting.json). ## Transactions The Vesting solidity interface includes the following transactions * `createClawbackVestingAccount` `createClawbackVestingAccount` defines a method for the creation of a `ClawbackVestingAccount`. ```solidity theme={null} function createClawbackVestingAccount( address funderAddress, address vestingAddress, bool enableGovClawback ) external returns (bool success); ``` * `fundVestingAccount` `fundVestingAccount` defines a method for funding a vesting account. ```solidity theme={null} function fundVestingAccount( address funderAddress, address vestingAddress, uint64 startTime, Period[] calldata lockupPeriods, Period[] calldata vestingPeriods ) external returns (bool success); ``` * `clawback` `clawback` defines a method for clawing back coins from a vesting account. ```solidity theme={null} function clawback( address funderAddress, address accountAddress, address destAddress ) external returns (Coin[] memory); ``` * `updateVestingFunder` `updateVestingFunder` defines a method for updating the funder of a vesting account. ```solidity theme={null} function updateVestingFunder( address funderAddress, address newFunderAddress, address vestingAddress ) external returns (bool success); ``` * `convertVestingAccount` `convertVestingAccount` defines a method for converting a clawback vesting account to an eth account. ```solidity theme={null} function convertVestingAccount( address vestingAddress ) external returns (bool success); ``` ## Queries * `balances` `balances` query the balances of a vesting account ```solidity theme={null} function balances( address vestingAddress ) external view returns (Coin[] memory locked, Coin[] memory unvested, Coin[] memory vested); ``` ## Events Each of the transactions emits its corresponding event. These are: * `CreateClawbackVestingAccount` Event that is emitted when a clawback vesting account is created. ```solidity theme={null} event CreateClawbackVestingAccount( address indexed funderAddress, address indexed vestingAddress ); ``` * `FundVestingAccount` Event that is emitted when a clawback vesting account is funded. ```solidity theme={null} event FundVestingAccount( address indexed funderAddress, address indexed vestingAddress, uint64 startTime, Period[] lockupPeriods, Period[] vestingPeriods ); ``` * `Clawback` Event that is emitted when a vesting account is clawed back. ```solidity theme={null} event Clawback( address indexed funderAddress, address indexed accountAddress, address destAddress ); ``` * `UpdateVestingFunder` Event that is emitted when a vesting account's funder is updated. ```solidity theme={null} event UpdateVestingFunder( address indexed funderAddress, address indexed vestingAddress, address newFunderAddress ); ``` * `ConvertVestingAccount` Event that is emitted when a vesting account is converted to a clawback vesting account. ```solidity theme={null} event ConvertVestingAccount( address indexed vestingAddress ); ``` # Smart Contracts Source: https://sidiorresearchlabs.mintlify.app/develop/smart-contracts/index Build and deploy smart contracts on HyperPaxeer EVM. # Smart Contracts Since the introduction of Ethereum in 2015, the ability to control digital assets through [smart contracts](https://ethereum.org/en/smart-contracts/) has attracted a large community of developers to build decentralized applications on the Ethereum Virtual Machine (EVM). This community is continuously creating extensive tooling and introducing standards, which are further increasing the adoption rate of EVM-compatible technology. Whether you are building new use cases on HyperPaxeer or porting an existing dApp from another EVM-based chain (e.g. Ethereum), you can easily build and deploy EVM smart contracts on HyperPaxeer to implement the core business logic of your dApp. HyperPaxeer is fully compatible with the EVM, so it allows you to use the same tools (Solidity, Remix, Oracles, etc.) and APIs (i.e. Ethereum JSON-RPC) that are available on the EVM. Leveraging the interoperability of Cosmos chains, HyperPaxeer enables you to build scalable cross-chain applications within a familiar EVM environment. Learn about the essential components when building and deploying EVM smart contracts on HyperPaxeer below. ## Build with Solidity You can develop EVM smart contracts on HyperPaxeer using [Solidity](https://github.com/ethereum/solidity). Solidity is also used to build smart contracts on Ethereum. So if you have deployed smart contracts on Ethereum (or any other EVM-compatible chain) you can use the same contracts on HyperPaxeer. Since it is the most widely used smart contract programming language in Blockchain, Solidity comes with well-documented and rich language support. Head over to our list of Tools and IDE Plugins to help you get started. ### EVM Extensions EVM Extensions are precompiled contracts that are built into the Ethereum Virtual Machine (EVM). Each offers specific functionality, that can be used by other smart contracts. Generally, they are used to perform operations that are either not possible or would be too expensive to perform with a regular smart contract implementation, such as hashing, elliptic curve cryptography, and modular exponentiation. By adding custom EVM extensions to Ethereum's basic feature set, HyperPaxeer allows developers to use previously unavailable functionality in smart contracts, like staking and governance operations. This will allow more complex smart contracts to be built on HyperPaxeer and further improves the interoperability between Cosmos and Ethereum. It also is a key feature to achieve HyperPaxeer' vision of being the definitive dApp chain, where any dApp can be deployed once and users can interact with a wide range of different blockchains natively. To enable the described functionalities, HyperPaxeer introduces so-called *stateful* precompiled smart contracts, which can perform a state transition, as opposed to those offered by the standard Go-Ethereum implementation, which can only read state information. This is necessary because an operation like e.g. staking tokens will ultimately change the chain state. View a list of available evm extensions [here](./list-evm-extensions.md). ### Oracles Blockchain oracles provide a way for smart contracts to access external information, such as price feeds from financial exchanges or carbon emission measurements. They serve as bridges between blockchains and the outside world. Head over to our [Oracles section](./oracles) to find out how smart contracts can make use of oracles on HyperPaxeer for real-life activities such as insurance, borrowing, lending, or gaming. ## Deploy with Ethereum JSON-RPC HyperPaxeer is fully compatible with the [Ethereum JSON-RPC](./../../develop/api/ethereum-json-rpc/) APIs, allowing you to deploy and interact with smart contracts on HyperPaxeer and connect with existing Ethereum-compatible web3 tooling. This gives you direct access to reading Ethereum-formatted transactions or sending them to the network which otherwise wouldn't be possible on a Cosmos chain, such as HyperPaxeer. You can connect to the HyperPaxeer [Testnet](./testnet) to deploy and test your smart contracts before moving to Mainnet. ### Block Explorers You can use [block explorers](./block-explorers) to view and debug interactions with your smart contracts deployed on HyperPaxeer. Block explorers index blocks and their transactions so that you can search for real-time and historical information about the blockchain, including data related to blocks, transactions, addresses, and more. ### Contract Verification Once deployed, smart contract data is deployed as non-human readable EVM bytecode. You can use [contract verification tools](./tools/contract-verifications) that publish and verify your original Solidity code to prove to users that they are interacting with the correct smart contract. ## HyperPaxeer Features The core protocol team is continuously building features that enhance the experience of smart contract developers on HyperPaxeer. Head over to our Mainnet sections to learn more about these functionalities. # EVM Extensions Source: https://sidiorresearchlabs.mintlify.app/develop/smart-contracts/list-evm-extensions Precompiled contracts and Cosmos module extensions available on HyperPaxeer mainnet ## Available extensions HyperPaxeer is mainnet-only today. The table below lists the extensions available on HyperPaxeer mainnet. | Address | Name | Stateful | Standard / source | Mainnet | | -------------------------------------------- | ------------------------------ | -------: | ------------------------------------------------- | ------- | | `0x0000000000000000000000000000000000000001` | ecRecover | No | Ethereum precompile | Active | | `0x0000000000000000000000000000000000000002` | SHA256 Hash | No | Ethereum precompile | Active | | `0x0000000000000000000000000000000000000003` | RIPEMD-160 Hash | No | Ethereum precompile | Active | | `0x0000000000000000000000000000000000000004` | Data Copy | No | Ethereum precompile | Active | | `0x0000000000000000000000000000000000000005` | ExpMod | No | [EIP-198](https://eips.ethereum.org/EIPS/eip-198) | Active | | `0x0000000000000000000000000000000000000006` | BN256Add | No | [EIP-196](https://eips.ethereum.org/EIPS/eip-196) | Active | | `0x0000000000000000000000000000000000000007` | BN256ScalarMul | No | [EIP-196](https://eips.ethereum.org/EIPS/eip-196) | Active | | `0x0000000000000000000000000000000000000008` | BN256Pairing | No | [EIP-197](https://eips.ethereum.org/EIPS/eip-197) | Active | | `0x0000000000000000000000000000000000000009` | Blake2F | No | [EIP-152](https://eips.ethereum.org/EIPS/eip-152) | Active | | `0x0000000000000000000000000000000000000400` | Bech32 encoding | No | HyperPaxeer extension | Active | | `0x0000000000000000000000000000000000000800` | Staking module | Yes | Cosmos SDK extension | Active | | `0x0000000000000000000000000000000000000801` | Distribution module | Yes | Cosmos SDK extension | Active | | `0x0000000000000000000000000000000000000802` | IBC Transfer | Yes | Cosmos SDK extension | Active | | `0x0000000000000000000000000000000000000803` | Vesting module | Yes | Cosmos SDK extension | Active | | `0x0000000000000000000000000000000000000901` | PaxSpot OROBResolver | No | PaxSpot precompile | Active | | `0x0000000000000000000000000000000000000902` | PaxSpot BatchClearing | No | PaxSpot precompile | Active | | `0x0000000000000000000000000000000000000903` | PaxSpot OracleAggregator / VOM | Mixed | PaxSpot + `x/paxoracle` precompile | Active | | `0x0000000000000000000000000000000000000904` | PaxSpot PoFQScorer | No | PaxSpot precompile | Active | Use the [PaxSpot precompile reference](/paxspot/precompiles) for Solidity and frontend examples for `0x901` through `0x904`. ## Further reading * [EVM precompiled contracts](https://www.evm.codes/precompiled) * [Current network facts](/current-network) * [PaxSpot precompiles](/paxspot/precompiles) # Client integrations Source: https://sidiorresearchlabs.mintlify.app/develop/tools/client-integrations # HyperPaxeer Client Integrations Client integration libraries play a crucial role in blockchain technology by making it easier for developers to interact with the blockchain network. Libraries abstract away complexities and provide integrations and methods to allow developers to create product in a more consistent manner. ## HyperPaxeer-specific Client Integrations HyperPaxeer-specific libraries are useful in aiding developers speed up development by providing interfaces, types, and methods to signing, address converter (between `eth` and `HyperPaxeer` addresses), and `EIP-712` transaction generator. There are two library bindings, in Javascript/Typescript and Python. * [HyperPaxeerJS](https://github.com/Paxeer-Network/Paxeer-Networkjs) - is the official HyperPaxeer client Typescript library. This library contains several packages: * [Address Converter](https://www.npmjs.com/package/@HyperPaxeer/address-converter) * [EIP-712](https://www.npmjs.com/package/@HyperPaxeer/eip712) * [Proto](https://www.npmjs.com/package/@HyperPaxeer/proto) * [Provider](https://www.npmjs.com/package/@HyperPaxeer/provider) * [Transactions](https://www.npmjs.com/package/@HyperPaxeer/transactions) * [PyHyperPaxeer](https://github.com/sterliakov/pyHyperPaxeer) - is a community-led Python library developed by [sterliakov](https://github.com/sterliakov) ## Ethereum Client Integrations EthersJS and Web3JS are two most commonly used libraries in dApp development. Developer uses these libraries to interact with blockchain and query JSON-RPC data, for example. Additionally, both of these libraries contain utilities to aid in task like converting large numbers (BigNumber). * [Ethers.js](https://docs.ethers.org/v5/) is the latest JS library that aims to be a complete and compact library for interacting with the Ethereum Blockchain and its ecosystem. * [web3js](https://web3js.readthedocs.io/en/v1.8.2/) is a collection of libraries that allow you to interact with a local or remote ethereum node using HTTP, IPC or WebSocket. # Contract verifications Source: https://sidiorresearchlabs.mintlify.app/develop/tools/contract-verifications # Contract Verification Contract verification refers to the process of auditing and verifying the code of smart contracts before they are deployed on the blockchain. This is an important step in ensuring that smart contracts function as intended and are free of vulnerabilities or security flaws. It is typically performed by independent auditors, security experts, or automated tools. The process involves a thorough analysis of the contract code to identify potential issues, such as bugs, security vulnerabilities, or potential attacks. This can involve both manual and automated testing to ensure that the code meets certain standards and best practices. ## [Escan](https://escan.live/) Escan is a service that allows block exploration as well as contract verification. For more information about the different block explorers, please proceed to our [block explorers's page](../block-explorers). [Link](https://escan.live/verifyContract) to verify and publish the contract source code. ## [Mintscan](https://www.mintscan.io/Paxeer-Network/evm) Mintscan, is another block explorer that offers permissioned contract verification. To view all the EVM contracts, proceed to [this link](https://www.mintscan.io/Paxeer-Network/evm). Verified contracts will have a green checkbox. To submit your contract for verification, please head to this [link](https://docs.google.com/forms/d/e/1FAIpQLScid7oF2ajNFG8xSwRupU_fgYOB-oqZVK-8bYScj_LsLB-Ejw/viewform) and fill out as much of the request detail. The Mintscan team will review the contract and get back to you. # Tools & Plugins Source: https://sidiorresearchlabs.mintlify.app/develop/tools/index Development tools, SDKs, and plugins for building on Paxeer. # Other Tools Tools play a crucial role in blockchain development as they help streamline the development process and make it easier for developers to build and deploy decentralized applications (dApps). Decentralized applications (dApps) are built on blockchain technology, which requires specific tools and frameworks for development. Some of the most commonly used tools in dApp development include: * [Tools and Plugins](./tools-plugins.md): There are many tools and plugins to aid in the development of dApps. These include smart contract languages and frameworks, development environments, wallet and identity management plugins, and analytics and monitoring tools. * [Client Integration](./client-integrations.md): HyperPaxeerJS and PyHyperPaxeer are two examples of client integration toolings to help developers interact with our core protocol features by providing interfaces, types, signing abstractions, and more. * [Contract Verifications](./contract-verifications.md): This is an important process in blockchain development that involves validating the authenticity and accuracy of smart contract code before deploying it to the blockchain. Contract verification serves to increase transparency, improves contract accuracy, prevents fraud and malicious activities, and increases adoption. Dive in further into the above toolings by visiting the subsequent pages. # Wallet Integration Source: https://sidiorresearchlabs.mintlify.app/develop/wallet-integration/index Integrate wallets like MetaMask and Keplr into your dApp. # Wallet Integration Wallet integration is an essential aspect of dApp development that allows users to securely interact with blockchain-based applications. Here are some key points from various sources on wallet integration in dApp development: * The integration implementation checklist for dApp developers consists of three categories: frontend features, transactions and wallet interactions, and more. Developers enabling transactions on their dApp have to determine the wallet type of the user, create the transaction, request signatures from the corresponding wallet, and finally broadcast. * Leverage Keplr, Metamask, Ledger, WalletConnect and more with HyperPaxeer. The latest wallets are located [here](https://academy.evmosd.org/articles/wallet). * Head over to our [HyperPaxeer Client Integrations](./../../develop/tools/client-integrations) to leverage our Typescript or Python libraries. ## Gas & Estimation When developing and running dApps on HyperPaxeer, the wallet configuration will attempt to calculate the correct gas amount for user's to sign. [Gas and Fees](./../../../protocol/concepts/gas-and-fees) breaks down these concepts in more detail. We have a module called [feemarket](./../../../protocol/modules/feemarket#concepts) that describes our module implementation of transaction prioritization since prior to Cosmos SDK 0.46 it did not have such implementation. # Code Examples Source: https://sidiorresearchlabs.mintlify.app/examples Integration guides and code samples for building on HyperPaxeer ## Overview Code examples and integration guides for building on HyperPaxeer. All examples work with standard Ethereum tools and libraries. ## Wallet Connection ### Connect Wallet with wagmi React component for connecting wallets to HyperPaxeer. ```typescript WalletConnect.tsx theme={null} 'use client' import { useAccount, useConnect, useDisconnect } from 'wagmi' import { Button } from '@/components/ui/button' export function WalletConnect() { const { address, isConnected } = useAccount() const { connect, connectors } = useConnect() const { disconnect } = useDisconnect() if (isConnected) { return (

Connected: {address}

) } return (
{connectors.map((connector) => ( ))}
) } ``` Make sure you've configured wagmi with HyperPaxeer in your `wagmi-config.ts` file.
### Connect Wallet with ethers.js ```javascript theme={null} import { ethers } from 'ethers'; async function connectWallet() { if (typeof window.ethereum === 'undefined') { alert('Please install MetaMask!'); return; } try { // Request account access const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' }); // Create provider const provider = new ethers.BrowserProvider(window.ethereum); const signer = await provider.getSigner(); const address = await signer.getAddress(); const balance = await provider.getBalance(address); console.log('Connected:', address); console.log('Balance:', ethers.formatEther(balance), 'HPX'); return { provider, signer, address }; } catch (error) { console.error('Error connecting wallet:', error); } } // Usage const wallet = await connectWallet(); ``` ### Connect with Web3Modal ```typescript theme={null} import { createWeb3Modal, defaultWagmiConfig } from '@web3modal/wagmi/react' import { WagmiConfig } from 'wagmi' import { paxeer } from './chains' const projectId = 'YOUR_PROJECT_ID' const metadata = { name: 'My dApp', description: 'My dApp description', url: 'https://myapp.com', icons: ['https://myapp.com/icon.svg'] } const chains = [paxeer] const wagmiConfig = defaultWagmiConfig({ chains, projectId, metadata }) createWeb3Modal({ wagmiConfig, projectId, chains }) function App() { return ( ) } ```
## Send Transactions ### Send Native HPX Tokens ```typescript SendPax.tsx theme={null} 'use client' import { useSendTransaction } from 'wagmi' import { parseEther } from 'viem' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { useState } from 'react' export function SendPax() { const [to, setTo] = useState('') const [amount, setAmount] = useState('') const { sendTransaction, data, isPending, isSuccess } = useSendTransaction() const handleSend = () => { sendTransaction({ to: to as `0x${string}`, value: parseEther(amount), }) } return (
setTo(e.target.value)} /> setAmount(e.target.value)} /> {isSuccess && (

Transaction: {data}

)}
) } ```
### Send Transaction with ethers.js ```javascript theme={null} import { ethers } from 'ethers'; async function sendTransaction(toAddress, amount) { const provider = new ethers.BrowserProvider(window.ethereum); const signer = await provider.getSigner(); const tx = { to: toAddress, value: ethers.parseEther(amount) }; try { const transaction = await signer.sendTransaction(tx); console.log('Transaction sent:', transaction.hash); // Wait for confirmation const receipt = await transaction.wait(); console.log('Transaction confirmed:', receipt.hash); return receipt; } catch (error) { console.error('Error sending transaction:', error); throw error; } } // Usage await sendTransaction('0x...', '1.5'); ```
## Contract Interactions ### Read Contract Data ```typescript TokenBalance.tsx theme={null} 'use client' import { useReadContract } from 'wagmi' import { formatUnits } from 'viem' const ERC20_ABI = [ { name: 'balanceOf', type: 'function', stateMutability: 'view', inputs: [{ name: 'owner', type: 'address' }], outputs: [{ name: 'balance', type: 'uint256' }], }, { name: 'decimals', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ name: '', type: 'uint8' }], }, ] as const export function TokenBalance({ address, tokenAddress }: { address: string; tokenAddress: string }) { const { data: balance, isLoading: balanceLoading } = useReadContract({ address: tokenAddress as `0x${string}`, abi: ERC20_ABI, functionName: 'balanceOf', args: [address as `0x${string}`], }) const { data: decimals } = useReadContract({ address: tokenAddress as `0x${string}`, abi: ERC20_ABI, functionName: 'decimals', }) if (balanceLoading) return
Loading...
const formattedBalance = balance && decimals ? formatUnits(balance, decimals) : '0' return (
Balance: {formattedBalance} tokens
) } ```
### Write to Contract ```typescript TransferTokens.tsx theme={null} 'use client' import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi' import { parseUnits } from 'viem' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { useState } from 'react' const ERC20_ABI = [ { name: 'transfer', type: 'function', stateMutability: 'nonpayable', inputs: [ { name: 'to', type: 'address' }, { name: 'amount', type: 'uint256' } ], outputs: [{ name: '', type: 'bool' }], }, ] as const export function TransferTokens({ tokenAddress }: { tokenAddress: string }) { const [to, setTo] = useState('') const [amount, setAmount] = useState('') const { data: hash, writeContract, isPending } = useWriteContract() const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash }) async function handleTransfer() { writeContract({ address: tokenAddress as `0x${string}`, abi: ERC20_ABI, functionName: 'transfer', args: [ to as `0x${string}`, parseUnits(amount, 18) ], }) } return (
setTo(e.target.value)} /> setAmount(e.target.value)} /> {isSuccess && (
Transfer successful! View transaction
)}
) } ```
### Contract Interaction with ethers.js ```javascript theme={null} import { ethers } from 'ethers'; const ERC20_ABI = [ "function balanceOf(address owner) view returns (uint256)", "function transfer(address to, uint256 amount) returns (bool)", "function decimals() view returns (uint8)" ]; async function interactWithToken(tokenAddress) { const provider = new ethers.BrowserProvider(window.ethereum); const signer = await provider.getSigner(); // Create contract instance const contract = new ethers.Contract( tokenAddress, ERC20_ABI, signer ); // Read balance const address = await signer.getAddress(); const balance = await contract.balanceOf(address); const decimals = await contract.decimals(); console.log('Balance:', ethers.formatUnits(balance, decimals)); // Transfer tokens const tx = await contract.transfer( '0xRecipientAddress', ethers.parseUnits('10', decimals) ); console.log('Transaction sent:', tx.hash); const receipt = await tx.wait(); console.log('Transfer confirmed:', receipt.hash); return receipt; } // Usage await interactWithToken('0xTokenAddress'); ```
## Event Listening ### Listen to Contract Events ```typescript useTokenTransfers.ts theme={null} import { useWatchContractEvent } from 'wagmi' import { useState } from 'react' const ERC20_ABI = [ { name: 'Transfer', type: 'event', inputs: [ { indexed: true, name: 'from', type: 'address' }, { indexed: true, name: 'to', type: 'address' }, { indexed: false, name: 'value', type: 'uint256' } ], }, ] as const export function useTokenTransfers(tokenAddress: string) { const [transfers, setTransfers] = useState([]) useWatchContractEvent({ address: tokenAddress as `0x${string}`, abi: ERC20_ABI, eventName: 'Transfer', onLogs(logs) { setTransfers(prev => [...prev, ...logs]) }, }) return transfers } ``` ### Listen with ethers.js ```javascript theme={null} import { ethers } from 'ethers'; async function listenToTransfers(tokenAddress) { const provider = new ethers.JsonRpcProvider( 'https://public-rpc.paxeer.app/rpc' ); const contract = new ethers.Contract( tokenAddress, ['event Transfer(address indexed from, address indexed to, uint256 value)'], provider ); // Listen to Transfer events contract.on('Transfer', (from, to, value, event) => { console.log('Transfer detected:'); console.log('From:', from); console.log('To:', to); console.log('Value:', ethers.formatEther(value)); console.log('Transaction:', event.log.transactionHash); }); // Query past events const filter = contract.filters.Transfer(); const events = await contract.queryFilter(filter, -10000); console.log('Recent transfers:', events.length); } ``` ## Complete dApp Example Here's a complete example of a token transfer dApp: ```typescript App.tsx theme={null} 'use client' import { useState } from 'react' import { useAccount, useReadContract, useWriteContract } from 'wagmi' import { parseUnits, formatUnits } from 'viem' import { WalletConnect } from './WalletConnect' const TOKEN_ADDRESS = '0xYourTokenAddress' const ERC20_ABI = [ { name: 'balanceOf', type: 'function', stateMutability: 'view', inputs: [{ name: 'owner', type: 'address' }], outputs: [{ name: '', type: 'uint256' }], }, { name: 'transfer', type: 'function', stateMutability: 'nonpayable', inputs: [ { name: 'to', type: 'address' }, { name: 'amount', type: 'uint256' } ], outputs: [{ name: '', type: 'bool' }], }, ] as const export default function TokenTransferApp() { const { address, isConnected } = useAccount() const [recipient, setRecipient] = useState('') const [amount, setAmount] = useState('') const { data: balance } = useReadContract({ address: TOKEN_ADDRESS, abi: ERC20_ABI, functionName: 'balanceOf', args: address ? [address] : undefined, }) const { writeContract, isPending } = useWriteContract() const handleTransfer = () => { if (!recipient || !amount) return writeContract({ address: TOKEN_ADDRESS, abi: ERC20_ABI, functionName: 'transfer', args: [recipient as `0x${string}`, parseUnits(amount, 18)], }) } if (!isConnected) { return (
) } return (

Token Transfer

Your Balance

{balance ? formatUnits(balance, 18) : '0'} tokens

setRecipient(e.target.value)} placeholder="0x..." className="w-full p-2 border rounded" />
setAmount(e.target.value)} placeholder="0.0" className="w-full p-2 border rounded" />
) } ``` ## Best Practices Always handle errors gracefully: ```typescript theme={null} try { const tx = await writeContract({...}); await tx.wait(); } catch (error) { if (error.code === 'ACTION_REJECTED') { console.log('User rejected transaction'); } else if (error.code === 'INSUFFICIENT_FUNDS') { console.log('Insufficient funds'); } else { console.error('Transaction failed:', error); } } ``` Show loading states for better UX: ```typescript theme={null} const { isPending, isLoading, isSuccess } = useWriteContract(); if (isPending) return
Confirm in wallet...
; if (isLoading) return
Transaction pending...
; if (isSuccess) return
Success!
; ```
Estimate gas before transactions: ```javascript theme={null} const gasEstimate = await contract.transfer.estimateGas( toAddress, amount ); const gasLimit = gasEstimate * 120n / 100n; // 20% buffer ```
## Next Steps Set up your development environment Deploy your own contracts Explore all available methods Discover development tools # Paxeer Network Source: https://sidiorresearchlabs.mintlify.app/index Developer documentation for Paxeer Network β€” Alexandria Fork, HyperPaxeer runtime, Argus VM, and network-operated protocols **Chain ID:** `125` | **Cosmos:** `hyperpax_125-1` | **Token:** PAX (`ahpx`, 18 decimals) | **Bech32:** `pax` | **Block time:** 277 ms average | **Binary:** `hyperpaxd_2.0.3` ## The Network HyperPaxeer is a sovereign Proof-of-Stake blockchain purpose-built for capital orchestration. Running on the **Alexandria Fork**, it pairs a production EVM execution layer with the **Argus Virtual Machine (AVM)** β€” a C++ register-based runtime that handles risk, capital allocation, and funded smart-wallet management. The April 2026 performance report shows 10 active validators, 48 RPC nodes, 14 active regions, and 277 ms average block production. Genesis-to-report mainnet history 47 EVM RPC nodes online across 14 active regions Official average block time with 341 ms p95 *** ## Dual-VM Architecture ```text theme={null} Paxeer Network +----------------------+ +----------------------+ | EVM OS Layer |β–ˆ | Argus VM (AVM) |β–ˆ | Alexandria Fork |β–ˆ | C++ runtime, .avm |β–ˆ | Solidity contracts |β–ˆ | Risk engine |β–ˆ | Custom precompiles |β–ˆ | Capital orchestration|β–ˆ | 0x901–0x904 |β–ˆ | Smart wallet |β–ˆ | Standard EVM tooling|β–ˆ |ArgLang scripts (.arg)|β–ˆ +----------------------+β–ˆ +----------------------+β–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ CometBFT Consensus Β· Cosmos SDK Β· IBC ``` The **EVM OS** is the blockchain shell β€” consensus, networking, smart-contract execution, JSON-RPC. The **AVM** is the value engine β€” capital allocation, drawdown policy, funded-wallet lifecycle. Both layers communicate through on-chain contract boundaries (`IPaxSpotReader`, `IAllowanceProvider`). *** ## Quick Navigation Install a node with one command, connect a wallet, deploy a contract Deploy and verify contracts with Foundry, Hardhat, or Remix wagmi, viem, ethers.js, and web3.js setup snippets Deploy RPC or Validator nodes with HyperPaxeer tooling *** ## Core Technology Register-based VM with 256-bit native arithmetic, deterministic gas metering, and the ArgLang smart-contract language Four stateful/stateless precompiles at 0x901–0x904 β€” OROB resolution, batch clearing, oracle aggregation, PoFQ scoring Native fungible-token spec for ArgusVM β€” Rust-inspired syntax, built-in overflow protection, optimised gas Cosmos SDK module for validator-submitted price feeds with confidence-weighted median aggregation *** ## Ecosystem Protocols On-chain spot exchange with Oracle-Relative Order Book (OROB), dual-mode matching, lazy-netting settlement, and capital-integrated trading Adaptive Sigmoid AMM β€” tanh bonding curve, progressive quadratic fees, LP loyalty rewards, oracle-pegged pools, Diamond Standard upgradeability Network-operated perpetual futures protocol with Diamond facets, on-chain order book, and oracle pricing Launchpad AMM with virtual USDL reserves, per-pool Beacon proxies, and Opticals Meta-AG routing layer for Paxeer liquidity, adapters, quotes, and execution tracking REST API for querying transactions, blocks, addresses, and tokens on PaxScan *** ## Network Details ```json theme={null} { "networkName": "HyperPaxeer", "rpcUrl": "https://public-rpc.paxeer.app/rpc", "chainId": 125, "cosmosChainId": "hyperpax_125-1", "currencySymbol": "PAX", "baseDenom": "ahpx", "displayDenom": "hpx", "decimals": 18, "bech32Prefix": "pax", "blockExplorer": "https://paxscan.io", "averageBlockTime": "277ms", "binary": "hyperpaxd_2.0.3" } ``` *** ## Developer Resources Test Ethereum JSON-RPC, Cosmos gRPC, and CometBFT RPC methods End-to-end integration samples in TypeScript, Python, and Solidity Foundry, Hardhat, wagmi, viem, cosmjs, and hpx CLI Live node health, latency benchmarks, and validator set # Network Status Source: https://sidiorresearchlabs.mintlify.app/network-status Live node health, latency benchmarks, and validator set for HyperPaxeer ## Validator Set HyperPaxeer runs on 10 active validators with balanced voting power. Consensus requires a two-thirds supermajority of voting power. | Metric | Value | | -------------------- | ----------------: | | Active validators | `10` | | Total voting power | `167,294,521` | | Voting-power range | `5.9%` to `13.1%` | | Nakamoto coefficient | `4` | Data from the official April 2026 HyperPaxeer performance report. *** ## Block Timing | Metric | Value | | ------------ | --------------------- | | **Average** | 277 ms | | **Min** | 197 ms | | **Max** | 358 ms | | **p95** | 341 ms | | **Std Dev** | 40.3 ms | | **Finality** | Instant deterministic | *** ## RPC / Full Node Fleet 48 RPC nodes and 47 EVM RPC nodes are online across 14 active regions. | Region group | Observed latency | | ------------- | ---------------: | | Best RPC | 4.2 ms | | Europe | 4-65 ms | | United States | 215-390 ms | *** ## Chain Statistics | Metric | Value | | ---------------- | ---------------------------------------------- | | **Chain ID** | `hyperpax_125-1` (EVM: `125`) | | **Block Height** | 5.25M+ blocks in the report sample | | **Genesis** | Block 1 (all nodes retain full history) | | **Consensus** | CometBFT v0.38.15 (PoS) | | **Fork** | Alexandria (Cosmos SDK + CometBFT) | | **Binary** | `hyperpaxd_2.0.3` | | **Token** | HPX (`ahpx` base / `hpx` display, 18 decimals) | *** ## Endpoints | Type | URL | | ------------------ | ------------------------------------- | | **JSON-RPC (EVM)** | `https://public-rpc.paxeer.app/rpc` | | **CometBFT RPC** | `https://public-rpc.paxeer.app:26657` | | **REST API** | `https://public-rpc.paxeer.app:1317` | | **gRPC** | `https://public-rpc.paxeer.app:9090` | | **Block Explorer** | [paxscan.io](https://paxscan.io) | *** ## Resources Deploy your own RPC or Validator node with the hpx CLI View live chain data on PaxScan # API Reference Source: https://sidiorresearchlabs.mintlify.app/openapi/index Explore and test HyperPaxeer APIs directly from the docs. # API Reference Explore HyperPaxeer APIs interactively. This section includes GraphQL schemas for our indexer services and OpenAPI specifications for REST APIs. ## GraphQL APIs Real-time indexer data via GraphQL: * **[LaunchPad GraphQL](/docs/openapi/launchpad-graphql)** - Bonding curve markets, swaps, and token launches * **[Perpetuals GraphQL](/docs/openapi/perpetual-graphql)** - Perpetual futures positions, trades, and liquidations * **[StableSwap GraphQL](/docs/openapi/stableswap-graphql)** - Stable AMM pools, swaps, and liquidity ## OpenAPI / JSON-RPC Interactive API playgrounds for REST and RPC endpoints: # LaunchPad GraphQL Source: https://sidiorresearchlabs.mintlify.app/openapi/launchpad-graphql GraphQL schema for the Paxeer LaunchPad indexer. # LaunchPad GraphQL Schema GraphQL schema for the LaunchPad indexer β€” bonding curve markets, swaps, transfers, holders, and candle data. **Endpoint:** `https://launchpad-indexer-production.up.railway.app/graphql` ## Schema ```graphql theme={null} type Market { id: Int! poolAddress: String! tokenAddress: String! nftId: Int! creator: String! name: String! symbol: String! metadata: JSON metadataImageUrl: String virtualReserveUSD: String! realReserveUSD: String! reserveToken: String! spotPrice: String! marketCap: String! volume24h: String! volumeTotal: String! trades24h: Int! tradesTotal: Int! feeStrategy: Int! volatility: Int! holders: Int! createdAtBlock: Int! createdAt: String! updatedAt: String! } type Swap { id: Int! txHash: String! poolAddress: String! sender: String! stablecoinIn: String stablecoinOut: String tokenIn: String! tokenOut: String! amountIn: String! amountOut: String! feeAmount: String! reserveUsdAfter: String! reserveTokenAfter: String! priceUsd: String! blockNumber: Int! timestamp: String! } type TokenTransfer { id: Int! txHash: String! tokenAddress: String! fromAddress: String! toAddress: String! amount: String! blockNumber: Int! timestamp: String! } type FeeClaim { id: Int! txHash: String! poolAddress: String nftId: Int! recipient: String! amount: String! blockNumber: Int! timestamp: String! } type Holder { holderAddress: String! balance: String! percentage: Float! } type Candle { openTime: String! open: String! high: String! low: String! close: String! volume: String! trades: Int! } type TokenMetadata { tokenAddress: String! name: String! symbol: String! metadata: JSON imageUrl: String description: String links: JSON } type VolatilitySnapshot { volatility: Int! blockNumber: Int! timestamp: String! } type IndexerStatus { lastBlock: Int! headBlock: Int lag: Int marketsIndexed: Int! totalSwaps: Int! totalTransfers: Int! uptime: String! } scalar JSON type Query { markets(orderBy: MarketOrderBy, limit: Int, offset: Int): [Market!]! market(poolAddress: String, tokenAddress: String, symbol: String): Market marketsByCreator(creator: String!): [Market!]! searchMarkets(query: String!): [Market!]! trendingMarkets(limit: Int): [Market!]! swaps(poolAddress: String!, limit: Int, offset: Int): [Swap!]! swapsByUser(sender: String!, limit: Int, offset: Int): [Swap!]! recentSwaps(limit: Int): [Swap!]! tokenTransfers(tokenAddress: String!, limit: Int, offset: Int): [TokenTransfer!]! transfersByAddress(address: String!, limit: Int, offset: Int): [TokenTransfer!]! topHolders(tokenAddress: String!, limit: Int): [Holder!]! holderCount(tokenAddress: String!): Int! feeClaims(nftId: Int!, limit: Int): [FeeClaim!]! candles(poolAddress: String!, interval: String!, limit: Int): [Candle!]! tokenMetadata(tokenAddress: String!): TokenMetadata volatilityHistory(poolAddress: String!, limit: Int): [VolatilitySnapshot!]! indexerStatus: IndexerStatus! } enum MarketOrderBy { MARKET_CAP_DESC MARKET_CAP_ASC VOLUME_DESC CREATED_DESC CREATED_ASC PRICE_DESC HOLDERS_DESC } type Subscription { marketUpdated(poolAddress: String): Market newSwap(poolAddress: String): Swap newMarket: Market } ``` # Perpetuals GraphQL Source: https://sidiorresearchlabs.mintlify.app/openapi/perpetual-graphql GraphQL schema for the Paxeer Perpetuals indexer. # Perpetuals GraphQL Schema GraphQL schema for the Perpetuals indexer β€” markets, positions, trades, orders, liquidations, funding rates, and vault operations. **Endpoint:** `https://perps.sidiora.xyz/api/subgraph` ## Schema ```graphql theme={null} directive @oneOf on INPUT_OBJECT scalar BigDecimal scalar DateTime type Market { marketId: Int! name: String! symbol: String! maxLeverage: BigDecimal! enabled: Boolean! createdAt: DateTime latestPrice: LatestPrice poolState: PoolState fundingRate: FundingRate } type Position { positionId: BigDecimal! userAddress: String! marketId: Int! isLong: Boolean! sizeUsd: BigDecimal! leverage: BigDecimal! entryPrice: BigDecimal! collateralToken: String collateralAmount: BigDecimal! collateralUsd: BigDecimal! status: String! realizedPnl: BigDecimal exitPrice: BigDecimal openedAt: DateTime closedAt: DateTime openBlock: Int closeBlock: Int openTxHash: String closeTxHash: String market: Market } type Trade { id: Int! positionId: BigDecimal! userAddress: String marketId: Int tradeType: String! isLong: Boolean sizeUsd: BigDecimal! price: BigDecimal! realizedPnl: BigDecimal feeUsd: BigDecimal blockNumber: Int! txHash: String! blockTimestamp: DateTime! } type Order { orderId: BigDecimal! userAddress: String! marketId: Int! orderType: Int! isLong: Boolean! triggerPrice: BigDecimal! sizeUsd: BigDecimal! status: String! positionId: BigDecimal executionPrice: BigDecimal placedAt: DateTime resolvedAt: DateTime placedBlock: Int resolvedBlock: Int placedTxHash: String resolvedTxHash: String } type Liquidation { id: Int! positionId: BigDecimal! userAddress: String! marketId: Int! price: BigDecimal! penalty: BigDecimal! keeper: String! blockNumber: Int! txHash: String! blockTimestamp: DateTime! } type PriceUpdate { id: Int! marketId: Int! price: BigDecimal! onchainTimestamp: Int! blockNumber: Int! txHash: String! blockTimestamp: DateTime! } type LatestPrice { marketId: Int! price: BigDecimal! onchainTimestamp: Int! blockNumber: Int! updatedAt: DateTime } type FundingRate { id: Int! marketId: Int! ratePerSecond: BigDecimal! rate24h: BigDecimal! blockNumber: Int! txHash: String! blockTimestamp: DateTime! } type UserVault { userAddress: String! vaultAddress: String! createdAt: DateTime blockNumber: Int txHash: String } type VaultEvent { id: Int! eventType: String! userAddress: String tokenAddress: String! amount: BigDecimal! blockNumber: Int! txHash: String! logIndex: Int! blockTimestamp: DateTime! } type CollateralToken { tokenAddress: String! decimals: Int! isActive: Boolean! addedAt: DateTime } type PoolState { marketId: Int! baseReserve: BigDecimal! quoteReserve: BigDecimal! oraclePrice: BigDecimal updatedAt: DateTime blockNumber: Int } type FeeConfig { takerFeeBps: Int! makerFeeBps: Int! liquidationFeeBps: Int! insuranceFeeBps: Int! updatedAt: DateTime } type ProtocolEvent { id: Int! eventName: String! eventData: String! blockNumber: Int! txHash: String! logIndex: Int! blockTimestamp: DateTime! } type IndexerStatus { lastIndexedBlock: Int! chainHead: Int blocksScanned: Int eventsProcessed: Int isSynced: Boolean } type UserStats { userAddress: String! totalPositions: Int! openPositions: Int! closedPositions: Int! liquidatedPositions: Int! totalTrades: Int! totalRealizedPnl: BigDecimal! totalOrders: Int! activeOrders: Int! } type MarketStats { marketId: Int! symbol: String totalPositions: Int! openPositions: Int! totalTrades: Int! totalLiquidations: Int! totalVolume: BigDecimal! latestPrice: BigDecimal latestFundingRate: BigDecimal } type GlobalStats { totalMarkets: Int! totalPositions: Int! openPositions: Int! totalTrades: Int! totalLiquidations: Int! totalVolume: BigDecimal! totalUsers: Int! indexerBlock: Int! } type Query { position(positionId: String!): Position positions(userAddress: String, marketId: Int, status: String, limit: Int, offset: Int): [Position!]! trades(userAddress: String, marketId: Int, positionId: String, tradeType: String, limit: Int, offset: Int): [Trade!]! order(orderId: String!): Order orders(userAddress: String, marketId: Int, status: String, limit: Int, offset: Int): [Order!]! liquidations(userAddress: String, marketId: Int, limit: Int, offset: Int): [Liquidation!]! market(marketId: Int!): Market markets: [Market!]! latestPrices: [LatestPrice!]! priceHistory(marketId: Int!, limit: Int, offset: Int): [PriceUpdate!]! fundingRates(marketId: Int!, limit: Int, offset: Int): [FundingRate!]! userVault(userAddress: String!): UserVault vaultEvents(userAddress: String, eventType: String, limit: Int, offset: Int): [VaultEvent!]! collateralTokens: [CollateralToken!]! poolStates: [PoolState!]! poolState(marketId: Int!): PoolState feeConfig: FeeConfig protocolEvents(eventName: String, limit: Int, offset: Int): [ProtocolEvent!]! userStats(userAddress: String!): UserStats marketStats(marketId: Int!): MarketStats globalStats: GlobalStats indexerStatus: IndexerStatus } ``` # StableSwap GraphQL Source: https://sidiorresearchlabs.mintlify.app/openapi/stableswap-graphql GraphQL schema for the Paxeer StableSwap indexer. # StableSwap GraphQL Schema GraphQL schema for the StableSwap indexer β€” pools, tokens, swaps, liquidity events, fee claims, and positions. **Endpoint:** `https://us-east-1.stable-swap.sidiora.exchange/graphql` ## Schema ```graphql theme={null} directive @oneOf on INPUT_OBJECT scalar BigDecimal scalar DateTime type protocol { id: String! } type pool { id: String! } type pools { first: Int skip: Int } type token { id: String! } type tokens { first: Int skip: Int } type swap { id: String! } type swaps { first: Int skip: Int poolId: String orderBy: String orderDirection: String } type liquidityEvents { first: Int skip: Int poolId: String orderBy: String orderDirection: String } type feeClaims { first: Int skip: Int poolId: String } type position { id: String! } type positions { first: Int skip: Int owner: String } type user { id: String! } type users { first: Int skip: Int } type indexerStatus { lastIndexedBlock: Int! chainHead: Int blocksScanned: Int eventsProcessed: Int isSynced: Boolean } ``` # PAX-28 Token Standard Source: https://sidiorresearchlabs.mintlify.app/pax-28 Native fungible token standard for ArgusVM β€” Rust-inspired syntax, built-in overflow protection, and register-optimised gas ## Overview PAX-28 is the native fungible token standard for HyperPaxeer, designed for **ArgusVM's register-based architecture** and the **ArgLang** smart-contract language. It provides the same functional surface as ERC-20 but with compile-time safety guarantees, optimised gas on register hardware, and Rust-inspired ergonomics. Designed for register-based execution β€” no stack overhead Automatic overflow/underflow protection at the language level Statically typed, Rust-inspired syntax that compiles to AVM bytecode *** ## Interface All HPX-28 compliant tokens must implement: ```arglang theme={null} trait HPX28 { pub view fn name() -> bytes; pub view fn symbol() -> bytes; pub view fn decimals() -> u256; pub view fn total_supply() -> u256; pub view fn balance_of(owner: address) -> u256; pub view fn allowance(owner: address, spender: address) -> u256; pub fn transfer(to: address, amount: u256) -> bool; pub fn transfer_from(from: address, to: address, amount: u256) -> bool; pub fn approve(spender: address, amount: u256) -> bool; } ``` ### Events ```arglang theme={null} event Transfer(from: address indexed, to: address indexed, amount: u256); event Approval(owner: address indexed, spender: address indexed, amount: u256); ``` *** ## Reference Implementation ```arglang theme={null} contract HPX28Token { state name: bytes; state symbol: bytes; state decimals: u256; state total_supply: u256; state balances: Map; state allowances: Map>; event Transfer(from: address indexed, to: address indexed, amount: u256); event Approval(owner: address indexed, spender: address indexed, amount: u256); init(name_: bytes, symbol_: bytes, decimals_: u256, initial_supply: u256) { name = name_; symbol = symbol_; decimals = decimals_; total_supply = initial_supply; balances[msg.sender] = initial_supply; emit Transfer(address(0), msg.sender, initial_supply); } pub view fn name() -> bytes { return name; } pub view fn symbol() -> bytes { return symbol; } pub view fn decimals() -> u256 { return decimals; } pub view fn total_supply() -> u256 { return total_supply; } pub view fn balance_of(owner: address) -> u256 { return balances[owner]; } pub view fn allowance(owner: address, spender: address) -> u256 { return allowances[owner][spender]; } pub fn transfer(to: address, amount: u256) -> bool { require(to != address(0), "transfer to zero address"); require(balances[msg.sender] >= amount, "insufficient balance"); balances[msg.sender] = balances[msg.sender] - amount; balances[to] = balances[to] + amount; emit Transfer(msg.sender, to, amount); return true; } pub fn transfer_from(from: address, to: address, amount: u256) -> bool { require(from != address(0), "transfer from zero address"); require(to != address(0), "transfer to zero address"); require(balances[from] >= amount, "insufficient balance"); require(allowances[from][msg.sender] >= amount, "insufficient allowance"); balances[from] = balances[from] - amount; balances[to] = balances[to] + amount; allowances[from][msg.sender] = allowances[from][msg.sender] - amount; emit Transfer(from, to, amount); return true; } pub fn approve(spender: address, amount: u256) -> bool { require(spender != address(0), "approve to zero address"); allowances[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } } ``` *** ## Storage Model PAX-28 uses Keccak256-based storage slot hashing, adapted for ArgusVM's register architecture: * **Simple state variables** get sequential slots (`counter` β†’ slot 0, `owner` β†’ slot 1) * **Maps** use `keccak256(key || base_slot)` for slot computation * **Nested maps** (e.g. allowances) apply hashing recursively: `keccak256(spender || keccak256(owner || base_slot))` ### Gas Costs | Operation | Gas (Estimated) | | ------------------------------ | ----------------------------- | | `balance_of()` / `allowance()` | \~251 gas (KECCAK256 + SLOAD) | | `transfer()` | \~21,000 gas | | `transfer_from()` | \~35,000 gas | | `approve()` | \~46,000 gas | Gas costs are lower than ERC-20 because register-based execution eliminates stack push/pop overhead for every intermediate value. *** ## Differences from ERC-20 | Aspect | ERC-20 | HPX-28 | | ------------------- | ----------------------------------------------------------- | -------------------------------------------------------- | | **Language** | Solidity (`function`, `mapping`) | ArgLang (`fn`, `Map`, `->` return types) | | **Overflow** | Requires SafeMath or Solidity 0.8+ checks | Built into language β€” all arithmetic reverts on overflow | | **VM** | Stack-based EVM | Register-based ArgusVM (32 x 256-bit registers) | | **Compilation** | Solidity β†’ EVM bytecode | ArgLang β†’ AVM bytecode (`.avm`) | | **Storage hashing** | `keccak256(key . slot)` (concatenation with period padding) | `keccak256(key \|\| slot)` (direct concatenation) | *** ## Optional Extensions ### HPX-28 Capped ```arglang theme={null} pub view fn cap() -> u256; pub fn mint(to: address, amount: u256) { require(total_supply + amount <= cap, "cap exceeded"); // mint logic } ``` ### HPX-28 Burnable ```arglang theme={null} pub fn burn(amount: u256) { require(balances[msg.sender] >= amount, "insufficient balance"); balances[msg.sender] -= amount; total_supply -= amount; emit Transfer(msg.sender, address(0), amount); } ``` ### HPX-28 Mintable ```arglang theme={null} pub fn mint(to: address, amount: u256) { require(msg.sender == minter, "only minter"); balances[to] += amount; total_supply += amount; emit Transfer(address(0), to, amount); } ``` *** ## Security Considerations * **Overflow protection** is automatic β€” no SafeMath needed * **Zero-address checks** prevent accidental token burns * **Approval race condition**: set allowance to 0 before changing, or use `increase_allowance()` / `decrease_allowance()` extensions * **Reentrancy**: follows checks-effects-interactions pattern β€” state changes before any external interaction *** ## Cross-Chain Compatibility PAX-28 is **not** bytecode-compatible with ERC-20 (different VM architecture). Cross-chain bridges must implement explicit translation: 1. Lock HPX-28 tokens on HyperPaxeer 2. Bridge translates to ERC-20 format 3. Mint equivalent ERC-20 on destination chain 4. Reverse: burn ERC-20, unlock HPX-28 The **CrossVerse Bridge** handles this translation natively. *** ## Status | Field | Value | | -------- | -------------- | | Standard | HPX-28 | | Status | Draft | | Category | Token Standard | | Network | HyperPaxeer | ## Resources Register set, ISA, gas model, and bytecode format Deploy contracts on HyperPaxeer # PaxSpot Source: https://sidiorresearchlabs.mintlify.app/paxspot On-chain spot trading system with oracle-relative orders, dual-mode matching, and capital-integrated execution ## Overview PaxSpot is a spot exchange built entirely in the EVM layer of HyperPaxeer. It introduces six novel primitives that exploit chain-level advantages β€” custom precompiles, validator-integrated keepers, and native gas policy β€” to deliver execution quality that no protocol on a shared chain can match. Orders stored as basis-point offsets from oracle price, not absolute prices Continuous in calm markets, sealed-bid batch auctions under volatility Funded smart wallets trade as first-class participants via Argus VM *** ## Six Primitives ### 1. Oracle-Relative Order Book (OROB) All orders and liquidity positions are stored as **basis-point offsets from the oracle price**, not absolute prices. A limit buy at "anchor - 5 bps" automatically follows the market. ``` Traditional: BUY 1 ETH @ $3,842.50 (stale in seconds) OROB: BUY 1 ETH @ anchor - 5 bps (always relative, auto-tracks) ``` * State compression: orders do not need repricing when the market moves * Fills outside configurable oracle bands are rejected (anti-manipulation) * LP positions track the market without active management * Resolution computed by **precompile `0x901`** (OROBResolver) β€” near-zero gas ### 2. Adaptive Dual-Mode Execution The protocol dynamically switches matching mode per market based on conditions: | Condition | Mode | Benefit | | -------------------------------- | --------------------------------------------------------------- | -------------------------- | | Normal / low volatility | **Continuous** β€” orders fill within the block they arrive | Fast UX, tight spreads | | High volatility / anomalous flow | **Sealed-bid batch auction** β€” uniform clearing price per block | MEV-immune, fair execution | Trigger logic (on-chain, per market): * Oracle confidence interval exceeds threshold * Block volume > 3 sigma of rolling 50-block average * Governance-configurable sensitivity Batch clearing price computed by **precompile `0x902`** (BatchClearing). ### 3. Programmable Liquidity Vaults (PLVs) Composable strategy vaults that implement a standard interface: ```solidity theme={null} interface ILiquidityVault { function quote(Side side, uint256 size, int256 oraclePrice, uint256 volatility) external view returns (int256 price, uint256 maxFillSize); function fill(Side side, uint256 size, int256 price) external returns (bool); function rebalance(int256 oraclePrice, int256 inventorySkew) external; } ``` Building blocks: constant-product, concentrated-range, sigmoid, and linear base curves with volatility-scaling, inventory-skew, and momentum overlay modifiers. A factory contract lets anyone compose new strategies by parameter configuration alone. ### 4. Proof-of-Fill-Quality (PoFQ) ``` fill_quality_score = 1 - |fill_price - oracle_price| / oracle_price ``` Every fill is scored against the oracle at execution time via **precompile `0x904`** (PoFQScorer). Vaults accumulate a rolling quality score on-chain. Higher score yields higher fee share, priority routing, and increased capital allocation from the Argus risk engine. ### 5. Lazy Netting Settlement ``` [Trade Execution] β†’ [Virtual Balance Update (same block)] β†’ [Net Settlement (every N blocks)] ``` * Users trade against virtual balances updated in the same block * Every settlement epoch (\~5 blocks / 10 s), the protocol computes net transfers across all participants * Gas reduction: 5–10x vs. per-trade settlement * **Fast-settle lane**: 1 bps premium for same-block finality ### 6. Capital-Integrated Trading PaxSpot interfaces with the **Argus VM** for funded smart-wallet trading: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ARGUS VM │────▢│ SMART WALLET │────▢│ HPXSPOT β”‚ β”‚ Risk engine │◀────│ Capital set │◀────│ PoFQ score β”‚ β”‚ Allocation β”‚ β”‚ by Argus β”‚ β”‚ PnL feed β”‚ β”‚ Drawdown β”‚ β”‚ Allowance β”‚ β”‚ Volume data β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` PaxSpot exposes `IPaxSpotReader` (PoFQ scores, PnL, positions) and enforces per-address limits via `IAllowanceProvider`. Funded wallets are indistinguishable from self-funded wallets at the matching-engine level. *** ## Contract Architecture PaxSpot is the exchange architecture layer for HyperPaxeer's spot markets. It relies on native precompiles for oracle-relative pricing, batch clearing, validator oracle aggregation, and fill-quality scoring. | Contract | Purpose | | -------------------- | ----------------------------------------------------------------------------------- | | **PaxSpotRouter** | Order gateway β€” signature validation, rate limiting, funded-wallet allowance checks | | **MatchingEngine** | OROB continuous + batch matching via precompiles `0x901`, `0x902`, and `0x904` | | **SettlementEngine** | Virtual-balance ledger, epoch netting, fast-settle lane | | **OracleAdapter** | Pyth primary + Validator Oracle Module (VOM) fallback via precompile 0x903 | ### Custom Precompiles | Address | Name | Type | Purpose | | -------------------------------------------- | ---------------------- | --------- | ------------------------------------------------------------------------ | | `0x0000000000000000000000000000000000000901` | OROBResolver | Stateless | Convert offset orders to absolute prices and back | | `0x0000000000000000000000000000000000000902` | BatchClearing | Stateless | Compute uniform clearing price for sealed-bid auctions | | `0x0000000000000000000000000000000000000903` | OracleAggregator / VOM | Mixed | Confidence-weighted median of validator-submitted prices (`x/paxoracle`) | | `0x0000000000000000000000000000000000000904` | PoFQScorer | Stateless | Score fill quality against oracle at execution time | See the [PaxSpot precompile reference](/paxspot/precompiles) for Solidity and TypeScript examples. *** ## Oracle Architecture PaxSpot uses a two-tier oracle with automatic fallback: 1. **Primary β€” Pyth Network**: Sub-second pull-oracle with confidence intervals 2. **Fallback β€” Validator Oracle Module (VOM)**: Validators submit prices via the `0x903` precompile (`submitPrice`). The `x/paxoracle` Cosmos SDK module aggregates submissions using a confidence-weighted median with staleness filtering (15-block threshold) and quorum enforcement. ```solidity theme={null} contract OracleAdapter { function getPrice(bytes32 feedId) external view returns (int256 price, uint256 confidence) { // Try Pyth first; fall back to VOM if stale or unavailable } } ``` *** ## Test Results **155 unit tests, 0 failures, 95.73% line coverage** (Foundry, `vm.mockCall` for precompiles). | Contract | Lines | Branches | Functions | | ---------------- | ------ | -------- | --------- | | MatchingEngine | 98.87% | 89.47% | 100% | | SettlementEngine | 98.06% | 100% | 94.74% | | PaxSpotRouter | 98.48% | 91.67% | 100% | | OracleAdapter | 96.25% | 83.33% | 100% | Local-chain integration tests (all passing): * Precompile 0x901 `resolveOffset` + `toOffset` * Precompile 0x902 `computeClearing` * Precompile 0x903 `submitPrice` + `getValidatorPrice` round-trip * Precompile 0x904 `scoreFill` * OracleAdapter `getPrice` (Pyth primary + VOM fallback) * MatchingEngine market creation + state query * PaxSpotRouter `submitOrder` end-to-end *** ## Resources Full technical specification General deployment and verification guide # PaxSpot Precompiles Source: https://sidiorresearchlabs.mintlify.app/paxspot/precompiles Solidity and frontend reference for the live PaxSpot precompiles at 0x901 through 0x904 ## Overview PaxSpot uses four custom EVM precompiles for exchange-critical computation. They run as native HyperPaxeer consensus code and are live on mainnet. | Address | Name | Purpose | | -------------------------------------------- | ---------------------- | ----------------------------------------------------------------------- | | `0x0000000000000000000000000000000000000901` | OROBResolver | Convert oracle-relative basis-point offsets to absolute prices and back | | `0x0000000000000000000000000000000000000902` | BatchClearing | Compute uniform clearing prices for batch auctions | | `0x0000000000000000000000000000000000000903` | OracleAggregator / VOM | Read validator oracle prices and submit validator attestations | | `0x0000000000000000000000000000000000000904` | PoFQScorer | Score fill quality against oracle prices | All price values in these examples use 18-decimal fixed point integers. ## `0x901` OROBResolver OROB orders store signed basis-point offsets from the oracle price instead of stale absolute prices. ```solidity theme={null} interface IOROBResolver { function resolveOffset(int256 oraclePrice, int16 offsetBps) external view returns (int256 absolutePrice); function resolveOffsetBatch(int256 oraclePrice, int16[] calldata offsetsBps) external view returns (int256[] memory absolutePrices); function toOffset(int256 oraclePrice, int256 absolutePrice) external view returns (int16 offsetBps); } ``` Formula: ```text theme={null} absolutePrice = oraclePrice * (10000 + offsetBps) / 10000 offsetBps = ((absolutePrice - oraclePrice) * 10000) / oraclePrice ``` ### Solidity example ```solidity theme={null} IOROBResolver constant OROB = IOROBResolver(0x0000000000000000000000000000000000000901); function limitPrice(int256 oraclePrice) external view returns (int256) { return OROB.resolveOffset(oraclePrice, -5); } ``` ### viem example ```typescript theme={null} import { createPublicClient, http, parseUnits } from 'viem' import { hyperpaxeer } from './chains' const client = createPublicClient({ chain: hyperpaxeer, transport: http('https://public-rpc.paxeer.app/rpc'), }) const price = await client.readContract({ address: '0x0000000000000000000000000000000000000901', abi: [{ type: 'function', name: 'resolveOffset', stateMutability: 'view', inputs: [ { name: 'oraclePrice', type: 'int256' }, { name: 'offsetBps', type: 'int16' }, ], outputs: [{ name: 'absolutePrice', type: 'int256' }], }], functionName: 'resolveOffset', args: [parseUnits('3842.50', 18), -5], }) ``` ## `0x902` BatchClearing BatchClearing computes the supply-demand crossing for a sealed-bid auction and returns a uniform clearing price. ```solidity theme={null} interface IBatchClearing { struct ClearingResult { int16 clearingOffsetBps; int256 clearingPrice; uint256 matchedVolume; } function computeClearing( int256 oraclePrice, int16[] calldata buyOffsets, uint128[] calldata buySizes, int16[] calldata sellOffsets, uint128[] calldata sellSizes ) external view returns (ClearingResult memory result); } ``` Input expectations: * `buyOffsets` are sorted from most aggressive to least aggressive. * `sellOffsets` are sorted from cheapest to most expensive. * `buySizes.length` must equal `buyOffsets.length`. * `sellSizes.length` must equal `sellOffsets.length`. * Empty buy or sell sides return zero matched volume. ```solidity theme={null} IBatchClearing constant CLEARING = IBatchClearing(0x0000000000000000000000000000000000000902); function previewBatch( int256 oraclePrice, int16[] calldata buyOffsets, uint128[] calldata buySizes, int16[] calldata sellOffsets, uint128[] calldata sellSizes ) external view returns (IBatchClearing.ClearingResult memory) { return CLEARING.computeClearing( oraclePrice, buyOffsets, buySizes, sellOffsets, sellSizes ); } ``` ## `0x903` OracleAggregator / VOM OracleAggregator reads validator-consensus prices from `x/paxoracle` and lets active validators submit price attestations. ```solidity theme={null} interface IOracleAggregator { function getValidatorPrice(bytes32 marketId) external view returns (int256 price, uint256 quorum, uint256 timestamp); function submitPrice(bytes32 marketId, int256 price, uint256 confidence) external returns (bool success); } ``` ### Read the validator price ```solidity theme={null} IOracleAggregator constant VOM = IOracleAggregator(0x0000000000000000000000000000000000000903); function readBtcPrice() external view returns (int256 price, uint256 quorum) { bytes32 marketId = keccak256("BTC/USD"); (price, quorum,) = VOM.getValidatorPrice(marketId); } ``` ### Submit a validator price `submitPrice()` is for active validators. Transactions from non-validator addresses are rejected by the oracle module. ```solidity theme={null} IOracleAggregator constant VOM = IOracleAggregator(0x0000000000000000000000000000000000000903); function submitBtcPrice(int256 price) external returns (bool) { bytes32 marketId = keccak256("BTC/USD"); uint256 confidence = 1e18; return VOM.submitPrice(marketId, price, confidence); } ``` ```typescript theme={null} import { createWalletClient, http, keccak256, parseUnits, stringToBytes } from 'viem' import { privateKeyToAccount } from 'viem/accounts' import { hyperpaxeer } from './chains' const account = privateKeyToAccount(process.env.VALIDATOR_EVM_PRIVATE_KEY as `0x${string}`) const wallet = createWalletClient({ account, chain: hyperpaxeer, transport: http('https://public-rpc.paxeer.app/rpc'), }) const hash = await wallet.writeContract({ address: '0x0000000000000000000000000000000000000903', abi: [{ type: 'function', name: 'submitPrice', stateMutability: 'nonpayable', inputs: [ { name: 'marketId', type: 'bytes32' }, { name: 'price', type: 'int256' }, { name: 'confidence', type: 'uint256' }, ], outputs: [{ name: 'success', type: 'bool' }], }], functionName: 'submitPrice', args: [ keccak256(stringToBytes('BTC/USD')), parseUnits('97250', 18), parseUnits('1', 18), ], }) ``` ## `0x904` PoFQScorer Proof-of-Fill-Quality scores execution quality relative to the oracle price. Scores range from `0` to `1e18`, where `1e18` means the fill matched the oracle price. ```solidity theme={null} interface IPoFQScorer { function scoreFill(int256 fillPrice, int256 oraclePrice) external view returns (uint256 score); function scoreBatch( int256[] calldata fillPrices, int256[] calldata oraclePrices, uint128[] calldata sizes ) external view returns (uint256 avgScore, uint256 totalVolume); function updateRollingScore( uint256 currentScore, uint256 currentWeight, uint256 newScore, uint256 newWeight, uint16 decayBps ) external view returns (uint256 updatedScore, uint256 updatedWeight); } ``` ```solidity theme={null} IPoFQScorer constant POFQ = IPoFQScorer(0x0000000000000000000000000000000000000904); function score(int256 fillPrice, int256 oraclePrice) external view returns (uint256) { return POFQ.scoreFill(fillPrice, oraclePrice); } ``` ## Related docs * [PaxSpot overview](/paxspot) * [x/paxoracle module](/protocol/modules/paxoracle) * [EVM extensions](/develop/smart-contracts/list-evm-extensions) # Performance Source: https://sidiorresearchlabs.mintlify.app/performance Official HyperPaxeer mainnet performance metrics, validator distribution, and RPC fleet data ## Summary The April 2026 performance report measures HyperPaxeer as a sub-second EVM L1 with deterministic CometBFT finality and a globally distributed RPC fleet. 197-358 ms observed range with 341 ms p95. CometBFT finality with `timeout_commit = 0`. 47 EVM RPC nodes online across 14 active regions. ## Block production | Metric | Value | | ------------------ | -----------------------------: | | Average block time | `277 ms` | | Minimum block time | `197 ms` | | Maximum block time | `358 ms` | | P95 block time | `341 ms` | | Standard deviation | `40.3 ms` | | Consensus engine | CometBFT `v0.38.15` | | `timeout_commit` | `0` | | Finality | Instant deterministic finality | ## Validator set | Metric | Value | | -------------------- | ----------------: | | Active validators | `10` | | Total voting power | `167,294,521` | | Voting-power range | `5.9%` to `13.1%` | | Nakamoto coefficient | `4` | The validator set is intentionally balanced: no validator controls enough voting power to dominate proposal or finality behavior alone. ## Chain activity | Metric | Value | | ------------------ | -----------: | | Blocks analyzed | `15.25M+` | | Transactions | `~2M` | | Unique addresses | `27K+` | | Contracts | `1.4K+` | | Live throughput | `0.41 tx/s` | | Peak block density | `3 tx/block` | | Active blocks | `11%` | Live throughput reflects current demand, not maximum chain capacity. ## Infrastructure | Metric | Value | | -------------------------- | -----------: | | RPC nodes online | `48` | | EVM RPC nodes online | `47` | | Active regions | `14` | | Best observed RPC latency | `4.2 ms` | | Europe latency band | `4-65 ms` | | United States latency band | `215-390 ms` | ## What developers should expect * Transactions confirm in the next finalized block under normal network conditions. * Public JSON-RPC is available at `https://public-rpc.paxeer.app/rpc`. * Use `paxscan.io` to inspect confirmed blocks, transactions, contracts, and addresses. * Contracts that assume Ethereum-like block cadence should be reviewed for sub-second block timing. ## Related docs * [Current network facts](/current-network) * [Network status](/network-status) * [Architecture overview](/concepts/architecture/overview) # Bugs Source: https://sidiorresearchlabs.mintlify.app/protocol/bugs # Bugs When creating a Layer 1 (L1) protocol chain, taking security seriously is of utmost importance. L1 protocols are the backbone of the blockchain ecosystem, and any security vulnerabilities within the L1 can lead to a range of potential consequences, from financial loss to reputation damage to even the collapse of the entire network. As such, security is an essential aspect of developing any L1 protocol chain, and security must be considered at every step of the development process. Check out our [Audits](./security/audits). Despite our best efforts, security issues may still arise in our L1 protocol chain. In such cases, we encourage our users to report any vulnerabilities or bugs they may find. For sensitive bugs, we ask that users submit the issue to [HyperPaxeer Security](mailto:security@HyperPaxeer.org), which is a third-party security platform that helps us identify, triage, and resolve security issues in a confidential and secure manner. For non-sensitive bugs, we encourage users to file an open ticket on our [HyperPaxeer Github Repo](https://github.com/Paxeer-Network/Paxeer-Network) so that our team can address the issue as quickly as possible. # Cli commands Source: https://sidiorresearchlabs.mintlify.app/protocol/cli/cli-commands # CLI Commands ## CLI Flags A list of commonly used flags of `hyperpaxd` is listed below: | Option | Description | Type | Default Value | | ------------------- | --------------------------------------------- | --------------- | ------------------------- | | `--chain-id` | Full Chain ID | `string` | `""` | | `--home` | Directory for config and data | `string` | `~/.hyperpaxd` | | `--keyring-backend` | Select keyring's backend | `string` | `"os"` | | `--output` | Output format | `string` | `"text"` | | `--node` | Tendermint RPC interface | `:` | `"tcp://localhost:26657"` | | `--from` | Name or address of account with which to sign | `string` | `""` | ## Command list A list of commonly used `hyperpaxd` commands. You can obtain the full list by using the `hyperpaxd -h` command. | Command | Description | Subcommands (example) | | ------------------ | --------------------------------------------------------------- | ------------------------------------------------------------------------- | | `keys` | Keys management | `list`, `show`, `add`, `add --recover`, `delete` | | `tx` | Transactions subcommands | `bank send`, `ibc-transfer transfer`, `distribution withdraw-all-rewards` | | `query` | Query subcommands | `bank balance`, `staking validators`, `gov proposals` | | `tendermint` | Tendermint subcommands | `show-address`, `show-node-id`, `version` | | `config` | Client configuration | | | `init` | Initialize full node | | | `start` | Run full node | | | `version` | HyperPaxeer version | | | `validate-genesis` | Validates the genesis file | | | `status` | Query remote node for status | | | `block` | Query a specific block persisted in the db (defaults to latest) | | # Configuration Source: https://sidiorresearchlabs.mintlify.app/protocol/cli/configuration # Configuration The following page will guide you through the configuration of a node and a client. The node is used to run the blockchain network, produce blocks and validate transactions. The client is used as a gateway to interact with the blockchain network by sending transactions and querying the state. Additionally we walk through [running the JSON-RPC server](#running-the-json-rpc-server). These configurations can impact the performance, security, and functionality of your node. Thus, understanding and correctly configuring your node and client is essential. ## Config and data directory By default, your config and data are stored in the folder located at the `~/.hyperpaxd` directory. You can easily change the default directory by using the `--home` flag. It is important to note that you can have multiple home directories that each represent a different blockchain. ```bash theme={null} . # ~/.hyperpaxd β”œβ”€β”€ data/ # Contains the databases used by the node. └── config/ β”œβ”€β”€ app.toml # Application-related configuration file. β”œβ”€β”€ config.toml # Tendermint-related configuration file. β”œβ”€β”€ genesis.json # The genesis file. β”œβ”€β”€ node_key.json # Private key to use for node authentication in the p2p protocol. └── priv_validator_key.json # Private key to use as a validator in the consensus protocol. ``` To specify the `hyperpaxd` config and data storage directory; you can update it using the global flag `--home `. ## Node Configuration The Cosmos SDK automatically generates two configuration files inside `~/.hyperpaxd/config`: * `config.toml`: used to configure the Tendermint, learn more on [Tendermint's documentation](https://docs.tendermint.com/v0.34/tendermint-core/configuration.html), * `app.toml`: generated by the Cosmos SDK, and used to configure your app, such as state pruning strategies, telemetry, gRPC and REST servers configuration, state sync, JSON-RPC, etc. Both files are heavily commented, please refer to them directly to tweak your node. One example config to tweak is the `minimum-gas-prices` field inside `app.toml`, which defines the minimum amount the validator node is willing to accept for processing a transaction. It is an anti spam mechanism and it will reject incoming transactions with less than the minimum gas prices. If it's empty, make sure to edit the field with some value, for example `10token`, or else the node will halt on startup. ```toml theme={null} # The minimum gas prices a validator is willing to accept for processing a # transaction. A transaction's fees must meet the minimum of any denomination # specified in this config (e.g. 0.25token1;0.0001token2). minimum-gas-prices = "0ahpx" ``` ### Pruning of State There are four strategies for pruning state. These strategies apply only to state and do not apply to block storage. To set pruning, adjust the `pruning` parameter in the `~/.hyperpaxd/config/app.toml` file. The following pruning state settings are available: * `everything`: Prune all saved states other than the current state. * `nothing`: Save all states and delete nothing. * `default`: Save the last 100 states and the state of every 10,000th block. * `custom`: Specify pruning settings with the `pruning-keep-recent`, `pruning-keep-every`, and `pruning-interval` parameters. By default, every node is in `default` mode which is the recommended setting for most environments. If you would like to change your nodes pruning strategy then you must do so when the node is initialized. Passing a flag when starting `HyperPaxeer` will always override settings in the `app.toml` file, if you would like to change your node to the `everything` mode then you can pass the `--pruning everything` flag when you call `hyperpaxd start`. :::warning **IMPORTANT**: When you are pruning state you will not be able to query the heights that are not in your store. ::: ## Client Configuration We can view the default client config setting by using `hyperpaxd config` command: ```bash theme={null} hyperpaxd config { "chain-id": "", "keyring-backend": "os", "output": "text", "node": "tcp://localhost:26657", "broadcast-mode": "sync" } ``` We can make changes to the default settings upon our choices, so it allows users to set the configuration beforehand all at once, so it would be ready with the same config afterward. For example, the chain identifier can be changed to `hyperpax_125-4` from a blank name by using: ```bash theme={null} hyperpaxd config "chain-id" hyperpax_125-4 hyperpaxd config { "chain-id": "hyperpax_125-4", "keyring-backend": "os", "output": "text", "node": "tcp://localhost:26657", "broadcast-mode": "sync" } ``` Other values can be changed in the same way. Alternatively, we can directly make the changes to the config values in one place at client.toml. It is under the path of `.hyperpaxd/config/client.toml` in the folder where we installed HyperPaxeer: ```toml theme={null} ############################################################################ ### Client Configuration ### ############################################################################ # The network chain ID chain-id = "hyperpax_125-4" # The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory) keyring-backend = "os" # CLI output format (text|json) output = "number" # : to Tendermint RPC interface for this chain node = "tcp://localhost:26657" # Transaction broadcasting mode (sync|async|block) broadcast-mode = "sync" ``` After the necessary changes are made in the `client.toml`, then save. For example, if we directly change the chain-id from `hyperpax_125-1` to a custom value, and output to number, it would change instantly as shown below. ```bash theme={null} hyperpaxd config { "chain-id": "hyperpax_125-1", "keyring-backend": "os", "output": "number", "node": "tcp://localhost:26657", "broadcast-mode": "sync" } ``` ## Running the JSON-RPC Server This section walks through the steps to enable the JSON-RPC server. JSON-RPC is provided on multiple transports. HyperPaxeer supports JSON-RPC over HTTP and WebSocket. In terms of requirements we recommend a server with minimum 8-core CPU and 64gb of RAM. You must have ports 8545 and 8546 open on your firewall. :::tip **Important**: You cannot use all JSON RPC methods unless your node stores the entire copy of the blockchain locally. Do you need archives/snapshots of our networks? Go to [this section](./../../develop/api/snapshots-archives). ::: ### Enable Server To enable RPC server use the following flag (set to true by default). ```bash theme={null} hyperpaxd start --json-rpc.enable ``` ### Defining Namespaces `Eth`,`Net` and `Web3` namespaces are enabled by default, but for the JSON-RPC you need to add more namespaces. In order to enable other namespaces edit `app.toml` file. ```toml theme={null} # API defines a list of JSON-RPC namespaces that should be enabled # Example: "eth,txpool,personal,net,debug,web3" api = "eth,net,web3,txpool,debug,personal" ``` ### Set a Gas Cap `eth_call` and `eth_estimateGas` define a global gas cap over rpc for DoS protection. You can override the default gas cap value of 25,000,000 by passing a custom value in `app.toml`: ```toml theme={null} # GasCap sets a cap on gas that can be used in eth_call/estimateGas (0=infinite). Default: 25,000,000. gas-cap = 25000000 ``` ### CORS If accessing the RPC from a browser, CORS will need to be enabled with the appropriate domain set. Otherwise, JavaScript calls are limit by the same-origin policy and requests will fail. The CORS setting can be updated from the `app.toml` ```toml theme={null} ############################################################################### ### API Configuration ### ############################################################################### [api] # ... # EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk). enabled-unsafe-cors = true # default false ``` ### Pruning For all methods to work correctly, your node must be archival (store the entire copy of the blockchain locally). Pruning must be disabled. The pruning settings can be updated from the `app.toml` ```toml theme={null} ############################################################################### ### Base Configuration ### ############################################################################### # The minimum gas prices a validator is willing to accept for processing a # transaction. A transaction's fees must meet the minimum of any denomination # specified in this config (e.g. 0.25token1;0.0001token2). # ... # default: the last 100 states are kept in addition to every 500th state; pruning at 10 block intervals # nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) # everything: all saved states will be deleted, storing only the current state; pruning at 10 block intervals # custom: allow pruning options to be manually specified through 'pruning-keep-recent', 'pruning-keep-every', > pruning = "nothing" pruning-keep-recent = "0" pruning-keep-every = "0" pruning-interval = "0" ``` ### WebSocket Server Websocket is a bidirectional transport protocol. A Websocket connection is maintained by client and server until it is explicitly terminated by one. Most modern browsers support Websocket which means it has good tooling. Because Websocket is bidirectional, servers can push events to clients. That makes Websocket a good choice for use-cases involving event subscription. Another benefit of Websocket is that after the handshake procedure, the overhead of individual messages is low, making it good for sending high number of requests. The WebSocket Server can be enabled from the `app.toml` ```toml theme={null} # Address defines the EVM WebSocket server address to bind to. ws-address = "0.0.0.0:8546" ``` # Working with Docker Source: https://sidiorresearchlabs.mintlify.app/protocol/cli/docker-build # Working with Docker There are multiple ways to use HyperPaxeer with Docker. If you want to run HyperPaxeer inside a Docker setup and possibly connect the Docker container to other containerized compatible blockchain binaries, check out the guide on [building a Docker image containing the HyperPaxeer binary](#building-a-docker-image-containing-the-binary). If you instead want to generate a binary for use outside of Docker, but want to ensure the correct dependencies are used by building the binary inside a Docker container, then go ahead to the section on [building the HyperPaxeer binary with Docker](#building-the-binary-with-docker). :::note The given instructions have been tested on *Ubuntu 18.04.2 LTS* with *Docker 20.10.2* and *macOS 13.2.1* with *Docker 20.10.22*. ::: ## Prerequisites * [Install Docker](https://docs.docker.com/get-docker/) ## General Setup In order to build HyperPaxeer binaries with Docker, it is necessary to * clone the HyperPaxeer repository to your local machine (e.g. `git clone git@github.com/Paxeer-Network/Paxeer-Network.git`) * checkout the commit, branch, or release tag you want to build (e.g. `git checkout v11.0.2`) ## Building A Docker Image Containing The Binary To build a Docker image, that contains the HyperPaxeer binary, step into the cloned repository and run the following command in a terminal session: ```bash theme={null} make build-docker ``` This will create an image with the name `tharsishq/Paxeer-Network` and the version tag `latest`. Now it is possible to run the `hyperpaxd` binary in the container, e.g. evaluating its version: ```bash theme={null} docker run -it --rm tharsishq/Paxeer-Network:latest hyperpaxd version ``` ## Building The Binary With Docker It is possible to build the `hyperpaxd` binary deterministically using Docker. The container system that Docker provides offers the ability to create an instance of the HyperPaxeer binary in an isolated environment. ### Building the Image Run the following command to launch a build for all supported architectures (currently **linux/amd64**): ```bash theme={null} make distclean build-reproducible ``` The build system generates both the binaries and deterministic build report in the `artifacts` directory. The `artifacts/build_report` file contains the list of the build artifacts and their respective checksums, and can be used to verify build sanity. An example of its contents follows: ``` App: hyperpaxd Version: 11.0.2 Commit: 8eeeac7ae42a5b2695fea7f56868f3c6e9bc2378 Files: 6b5939adfd9a8ce964d78fcaab16091a hyperpaxd-11.0.2-linux-amd64 ac503925c535ddb8ee0fbebbb96d0eb9 hyperpaxd-11.0.2.tar.gz Checksums-Sha256: 0857d59c285a87b7d354aa6d566db90c56663d938a88d41d35415da490708aea hyperpaxd-11.0.2-linux-amd64 5005814fc34abc02d7e30dcfbe67e363c1b593efb774e0c97ebb7ec713baf306 hyperpaxd-11.0.2.tar.gz ``` ### Builder Image The [Tendermint builder Docker image](https://github.com/tendermint/images/tree/master/rbuilder) provides a deterministic build environment that is used to build Cosmos SDK applications. It provides a way to be reasonably sure that the executables are really built from the git source. It also makes sure that the same, tested dependencies are used and statically built into the executable. *** Now that you have built the HyperPaxeer binary, either for local use or in a Docker container, you'll find information to run a node instance in the following section on [setting up a local network](./single-node). # CLI Source: https://sidiorresearchlabs.mintlify.app/protocol/cli/index Command-line tools and node operation guides. # HyperPaxeer CLI `hyperpaxd` is the all-in-one command-line interface (CLI). It allows you to run an HyperPaxeer node, manage wallets and interact with the HyperPaxeer network through queries and transactions. This introduction will explain how to install the `hyperpaxd` binary onto your system and guide you through some simple examples how to use hyperpaxd. ## Prerequisites #### Go HyperPaxeer is built using [Go](https://golang.org/dl/) version `1.20+`. Check your version with: ```bash theme={null} go version ``` Once you have installed the right version, confirm that your [`GOPATH`](https://golang.org/doc/gopath_code#GOPATH) is correctly configured by running the following command and adding it to your shell startup script: ```bash theme={null} export PATH=$PATH:$(go env GOPATH)/bin ``` #### jq HyperPaxeer scripts are using [jq](https://stedolan.github.io/jq/download/) version `1.6+`. Check your version with: ``` jq --version ``` ## Installation You can download the latest binaries from the repo and install them, or you can build and install the `hyperpaxd` binaries from source or using Docker. ### Download the binaries * Go to the [releases section of the repository](https://github.com/Paxeer-Network/Paxeer-Network/releases) * Choose the desired release or pre-release you want to install on your machine * Select and download from the `Assets` dropdown the corresponding tar or zip file for your OS * Extract the files. The `hyperpaxd` binaries is located in the `bin` directory of the extrated files * Add the `hyperpaxd` binaries to your path, e.g. you can move it to `$(go env GOPATH)/bin` After installation is done, check that the `hyperpaxd` binaries have been successfully installed: ```bash theme={null} hyperpaxd version ``` ### Build From Source Clone and build the HyperPaxeer from source using `git`. The `` refers to a release tag on Github. Check the latest HyperPaxeer version on the [releases section of the repository](https://github.com/Paxeer-Network/Paxeer-Network/releases): ```bash theme={null} git clone https://github.com/Paxeer-Network/Paxeer-Network.git cd HyperPaxeer git fetch git checkout make install ``` After installation is done, check that the hyperpaxd binaries have been successfully installed: ```bash theme={null} hyperpaxd version ``` :::info If the `hyperpaxd: command not found` error message is returned, confirm that you have configured [Go](#go) correctly. ::: ### Docker When it comes to using Docker with HyperPaxeer, there are two options available: Build a binary of the HyperPaxeer daemon inside a dockerized build environment or build a Docker image, that can be used to spin up individual containers running the HyperPaxeer binary. For information on how to achieve this, proceed to the dedicated page on [working with Docker](./docker-build.md). ## Run an HyperPaxeer node To become familiar with HyperPaxeer, you can run a local blockchain node that produces blocks and exposes EVM and Cosmos endpoints. This allows you to deploy and interact with smart contracts locally or test core protocol functionality. Run the local node by executing the `local_node.sh` script in the base directory of the repository: ```bash theme={null} ./local_node.sh ``` The script stores the node configuration including the local default endpoints under `~/.tmp-hyperpaxd/config/config.toml`. If you have previously run the script, the script allows you to overwrite the existing configuration and start a new local node. Once your node is running you will see it validating and producing blocks in your local HyperPaxeer blockchain: ```bash theme={null} 12:59PM INF executed block height=1 module=state num_invalid_txs=0 num_valid_txs=0 server=node # ... 1:00PM INF indexed block exents height=7 module=txindex server=node ``` For more information on how to customize a local node, head over to the [Single Node](./Paxeer-Network-cli/single-node) page. ## Using `hyperpaxd` After installing the `hyperpaxd` binary, you can run commands using: ```bash theme={null} hyperpaxd [command] ``` There is also a `-h`, `--help` command available ```bash theme={null} hyperpaxd -h ``` It is possible to maintain multiple node configurations at the same time. To specify a configuration use the `--home` flag. In the following examples we will be using the default config for a local node, located at `~/.tmp-hyperpaxd`. ### Manage wallets You can manage your wallets using the hyperpaxd binary to store private keys and sign transactions over CLI. To view all keys use: ```bash theme={null} hyperpaxd keys list \ --home ~/.tmp-hyperpaxd \ --keyring-backend test # Example Output: # - address: HyperPaxeer19xnmslvl0pcmydu4m52h2gf0std5ee5pfgpyuf # name: dev0 # pubkey: '{"@type":"/hyperpaxeer.crypto.v1.ethsecp256k1.PubKey","key":"AzKouyoUL0UUS1qRUZdqyVsTPkCAFWwxx3+BTOw36nKp"}' # type: local ``` You can generate a new key/mnemonic with a `$NAME` with: ```bash theme={null} hyperpaxd keys add [name] \ --home ~/.tmp-hyperpaxd \ --keyring-backend test ``` To export your HyperPaxeer key as an Ethereum private key (for use with [Metamask](https://academy.evmosd.org/articles/beginner/connect-your-wallet/metamask) for example): ```bash theme={null} hyperpaxd keys unsafe-export-eth-key [name] \ --home ~/.tmp-hyperpaxd \ --keyring-backend test ``` For more about the available key commands, use the `--help` flag ```bash theme={null} hyperpaxd keys -h ``` :::tip For more information about the Keyring and its backend options, click [here](../concepts/keyring.md). ::: ### Interact with a Network You can use hyperpaxd to query information or submit transactions on the blockchain. Queries and transactions are requests that you send to an HyperPaxeer node through the Tendermint RPC. :::tip πŸ‘‰ To use the CLI, you will need to provide a Tendermint RPC address for the `--node` flag. Look for a publicly available addresses for testnet and mainnet in the [Networks](./../../develop/api/networks) page. ::: #### Set Network Config In the local setup the node is set to `tcp://localhost:26657`. You can view your node configuration with: ```bash theme={null} hyperpaxd config \ --home ~/.tmp-hyperpaxd # Example Output # { # "chain-id": "hyperpax_125-1", # "keyring-backend": "test", # "output": "text", # "node": "tcp://localhost:26657", # "broadcast-mode": "sync" # } ``` You can set your node configuration to send requests to a different network by changing the endpoint with: ```bash theme={null} hyperpaxd config node [tendermint-rpc-endpoint] \ --home ~/.tmp-hyperpaxd ``` Learn about more node configurations [here](configuration.mdx). #### Queries You can query information on the blockchain using `hyperpaxd query` (short `hyperpaxd q`). To view the account balances by its address stored in the bank module, use: ```bash theme={null} hyperpaxd q bank balances [adress] \ --home ~/.tmp-hyperpaxd # # Example Output: # balances: # - amount: "99999000000000000000002500" # denom: ahpx ``` To view other available query commands, use: ```bash theme={null} # for all Queries hyperpaxd q # for querying commands in the bank module hyperpaxd q bank ``` #### Transactions You can submit transactions to the network using `hyperpaxd tx`. This creates, signs and broadcasts a tx in one command. To send tokens from an account in the keyring to another address with the bank module, use: ```bash theme={null} hyperpaxd tx bank send [from_key_or_address] [to_address] [amount] \ --home ~/.tmp-hyperpaxd \ --fees 50000000000ahpx \ -b block # Example Output: # ... # txhash: 7BA2618295B789CC24BB13E654D9187CDD264F61FC446EB756EAC07AF3E7C40A ``` To view other available transaction commands, use: ```bash theme={null} # for all transaction commands hyperpaxd tx # for Bank transaction subcommands hyperpaxd tx bank ``` Now that you've learned the basics of how to run and interact with an HyperPaxeer network, head over to [configurations](configuration.mdx) for futher customization. # Multi nodes Source: https://sidiorresearchlabs.mintlify.app/protocol/cli/multi-nodes # Multi Node Following this page, you can run a localnet setup with docker that consists of a 4-node local chain. This setup can be useful for developers to test their applications and protocol features on a multi-node setup. A similar setup is used by the HyperPaxeer team to get insights about the impact of new features and testing different user flows. This testing setup can be found on the [HyperPaxeer testing repository](https://github.com/Paxeer-Network/testing). ### Build & Start To build start a 4 node testnet using [docker](https://docs.docker.com/engine/installation/), run: ```bash theme={null} make localnet-start ``` This command creates a 4-node network using the `hyperpaxdnode` Docker image. The ports for each node are found in this table: | Node ID | P2P Port | Tendermint RPC Port | REST/ Ethereum JSON-RPC Port | WebSocket Port | | ------------------ | -------- | ------------------- | ---------------------------- | -------------- | | `HyperPaxeernode0` | `26656` | `26657` | `8545` | `8546` | | `HyperPaxeernode1` | `26659` | `26660` | `8547` | `8548` | | `HyperPaxeernode2` | `26661` | `26662` | `8549` | `8550` | | `HyperPaxeernode3` | `26663` | `26664` | `8551` | `8552` | To update the binary, just rebuild it and restart the nodes ```bash theme={null} make localnet-start ``` The command above command will run containers in the background using Docker compose. You will see the network being created: ```bash theme={null} ... Creating network "HyperPaxeer_localnet" with driver "bridge" Creating hyperpaxdnode0 ... done Creating hyperpaxdnode2 ... done Creating hyperpaxdnode1 ... done Creating hyperpaxdnode3 ... done ``` ### Stop Localnet Once you are done, execute: ```bash theme={null} make localnet-stop ``` ### Configuration The `make localnet-start` creates files for a 4-node testnet in `./build` by calling the `hyperpaxd testnet` command. This outputs a handful of files in the `./build` directory: ```bash theme={null} tree -L 3 build/ build/ β”œβ”€β”€ hyperpaxd β”œβ”€β”€ hyperpaxd β”œβ”€β”€ gentxs β”‚ β”œβ”€β”€ node0.json β”‚ β”œβ”€β”€ node1.json β”‚ β”œβ”€β”€ node2.json β”‚ └── node3.json β”œβ”€β”€ node0 β”‚ β”œβ”€β”€ hyperpaxd β”‚ β”‚ β”œβ”€β”€ key_seed.json β”‚ β”‚ └── keyring-test-cosmos β”‚ └── hyperpaxd β”‚ β”œβ”€β”€ config β”‚ β”œβ”€β”€ data β”‚ └── hyperpaxd.log β”œβ”€β”€ node1 β”‚ β”œβ”€β”€ hyperpaxd β”‚ β”‚ β”œβ”€β”€ key_seed.json β”‚ β”‚ └── keyring-test-cosmos β”‚ └── hyperpaxd β”‚ β”œβ”€β”€ config β”‚ β”œβ”€β”€ data β”‚ └── hyperpaxd.log β”œβ”€β”€ node2 β”‚ β”œβ”€β”€ hyperpaxd β”‚ β”‚ β”œβ”€β”€ key_seed.json β”‚ β”‚ └── keyring-test-cosmos β”‚ └── hyperpaxd β”‚ β”œβ”€β”€ config β”‚ β”œβ”€β”€ data β”‚ └── hyperpaxd.log └── node3 β”œβ”€β”€ hyperpaxd β”‚ β”œβ”€β”€ key_seed.json β”‚ └── keyring-test-cosmos └── hyperpaxd β”œβ”€β”€ config β”œβ”€β”€ data └── hyperpaxd.log ``` Each `./build/nodeN` directory is mounted to the `/hyperpaxd` directory in each container. ### Logging In order to see the logs of a particular node you can use the following command: ```bash theme={null} # node 0: daemon logs docker exec hyperpaxdnode0 tail hyperpaxd.log # node 0: REST & RPC logs docker exec hyperpaxdnode0 tail hyperpaxd.log ``` The logs for the daemon will look like: ```bash theme={null} I[2020-07-29|17:33:52.452] starting ABCI with Tendermint module=main E[2020-07-29|17:33:53.394] Can't add peer's address to addrbook module=p2p err="Cannot add non-routable address 272a247b837653cf068d39efd4c407ffbd9a0e6f@192.168.10.5:26656" E[2020-07-29|17:33:53.394] Can't add peer's address to addrbook module=p2p err="Cannot add non-routable address 3e05d3637b7ebf4fc0948bbef01b54d670aa810a@192.168.10.4:26656" E[2020-07-29|17:33:53.394] Can't add peer's address to addrbook module=p2p err="Cannot add non-routable address 689f8606ede0b26ad5b79ae244c14cc67ab4efe7@192.168.10.3:26656" I[2020-07-29|17:33:58.828] Executed block module=state height=88 validTxs=0 invalidTxs=0 I[2020-07-29|17:33:58.830] Committed state module=state height=88 txs=0 appHash=90CC5FA53CF8B5EC49653A14DA20888AD81C92FCF646F04D501453FD89FCC791 I[2020-07-29|17:34:04.032] Executed block module=state height=89 validTxs=0 invalidTxs=0 I[2020-07-29|17:34:04.034] Committed state module=state height=89 txs=0 appHash=0B54C4DB1A0DACB1EEDCD662B221C048C826D309FD2A2F31FF26BAE8D2D7D8D7 I[2020-07-29|17:34:09.381] Executed block module=state height=90 validTxs=0 invalidTxs=0 I[2020-07-29|17:34:09.383] Committed state module=state height=90 txs=0 appHash=75FD1EE834F0669D5E717C812F36B21D5F20B3CCBB45E8B8D415CB9C4513DE51 I[2020-07-29|17:34:14.700] Executed block module=state height=91 validTxs=0 invalidTxs=0 ``` :::tip You can disregard the `Can't add peer's address to addrbook` warning. As long as the blocks are being produced and the app hashes are the same for each node, there should not be any issues. ::: Whereas the logs for the REST & RPC server would look like: ```bash theme={null} I[2020-07-30|09:39:17.488] Starting application REST service (chain-id: "7305661614933169792")... module=rest-server I[2020-07-30|09:39:17.488] Starting RPC HTTP server on 127.0.0.1:8545 module=rest-server ... ``` #### Follow Logs You can also watch logs as they are produced via Docker with the `--follow` (`-f`) flag, for example: ```bash theme={null} docker logs -f hyperpaxdnode0 ``` ### Interact with the Localnet #### Ethereum JSON-RPC & Websocket Ports To interact with the testnet via WebSockets or RPC/API, you will send your request to the corresponding ports: | EVM JSON-RPC | Eth Websocket | | ------------ | ------------- | | `8545` | `8546` | You can send a curl command such as: ```bash theme={null} curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -H "Content-Type: application/json" 192.162.10.1:8545 ``` :::tip The IP address will be the public IP of the docker container. ::: Additional instructions on how to interact with the WebSocket can be found on the [events documentation](./../../develop/api/ethereum-json-rpc#ethereum-websocket). ### Keys & Accounts To interact with `hyperpaxd` and start querying state or creating txs, you use the `hyperpaxd` directory of any given node as your `home`, for example: ```bash theme={null} hyperpaxd keys list --home ./build/node0/hyperpaxd ``` Now that accounts exists, you may create new accounts and send those accounts funds! :::tip **Note**: Each node's seed is located at `./build/nodeN/hyperpaxd/key_seed.json` and can be restored to the CLI using the `hyperpaxd keys add --restore` command ::: ### Special Binaries If you have multiple binaries with different names, you can specify which one to run with the BINARY environment variable. The path of the binary is relative to the attached volume. For example: ```bash theme={null} # Run with custom binary BINARY=HyperPaxeer make localnet-start ``` # Single node Source: https://sidiorresearchlabs.mintlify.app/protocol/cli/single-node # Single Node Following this page, you can run a single node local network manually or by using the already prepared automated script. Running a single node setup is useful for developers who want to test their applications and protocol features because of its simplicity and speed. For more complex setups, please refer to the [Multi Node Setup](./multi-nodes) page. ## Prerequisite Readings * [Install Binary](./) ## Automated Script The simplest way to start a local HyperPaxeer node is by using the provided helper script on the base level of the [HyperPaxeer repository](https://github.com/Paxeer-Network/Paxeer-Network/blob/main/local_node.sh), which will create a sensible default configuration for testing purposes: ```bash theme={null} $ local_node.sh ... ``` :::tip To avoid overwriting any data for a real node used in production, it was decided to store the automatically generated testing configuration at `~/.tmp-hyperpaxd` instead of the default `~/.hyperpaxd`. ::: When working with the `local_node.sh` script, it is necessary to extend all `hyperpaxd` commands, that target the local test node, with the `--home ~/.tmp-hyperpaxd` flag. This is mandatory, because the `home` directory cannot be stored in the `hyperpaxd` configuration, which can be seen in the output below. For ease of use, it might be sensible to export this directory path as an environment variable: ``` $ export TMP=$HOME/.tmp-hyperpaxd` $ hyperpaxd config --home $TMP { "chain-id": "hyperpax_125-1", "keyring-backend": "test", "output": "text", "node": "tcp://localhost:26657", "broadcast-mode": "sync" } ``` You can customize the local node script by changing the configuration variables. See the following excerpt from the script for ideas on what can be adjusted: ```bash theme={null} # Customize the name of your keys, the chain-id, moniker of the node, keyring backend, and more KEYS[0]="dev0" KEYS[1]="dev1" KEYS[2]="dev2" CHAINID="hyperpax_125-1" MONIKER="localtestnet" # Remember to change to other types of keyring like 'file' in-case exposing to outside world, # otherwise your balance will be wiped quickly # The keyring test does not require private key to steal tokens from you KEYRING="test" KEYALGO="eth_secp256k1" LOGLEVEL="info" # Set dedicated home directory for the hyperpaxd instance HOMEDIR="$HOME/.tmp-hyperpaxd" # to trace evm #TRACE="--trace" TRACE="" [...] # Adjust this set a different maximum gas limit jq '.consensus_params["block"]["max_gas"]="10000000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" [...] ``` ## Manual Deployment This guide helps you create a single validator node that runs a network locally for testing and other development related uses. ### Initialize the chain Before actually running the node, we need to initialize the chain, and most importantly its genesis file. This is done with the `init` subcommand: ```bash theme={null} $MONIKER=testing $KEY=dev0 $CHAINID="hyperpax_125-4" # The argument $MONIKER is the custom username of your node, it should be human-readable. hyperpaxd init $MONIKER --chain-id=$CHAINID ``` :::tip You can [edit](./configuration#client-configuration) this `moniker` later by updating the `config.toml` file. ::: The command above creates all the configuration files needed for your node and validator to run, as well as a default genesis file, which defines the initial state of the network. All these [configuration files](./configuration#client-configuration) are in `~/.hyperpaxd` by default, but you can overwrite the location of this folder by passing the `--home` flag. ### Genesis Procedure ### Adding Genesis Accounts Before starting the chain, you need to populate the state with at least one account using the [keyring](./../../protocol/concepts/keyring#add-keys): ```bash theme={null} hyperpaxd keys add my_validator ``` Once you have created a local account, go ahead and grant it some `ahpx` tokens in your chain's genesis file. Doing so will also make sure your chain is aware of this account's existence: ```bash theme={null} hyperpaxd add-genesis-account my_validator 10000000000ahpx ``` Now that your account has some tokens, you need to add a validator to your chain. For this guide, you will add your local node (created via the `init` command above) as a validator of your chain. Validators can be declared before a chain is first started via a special transaction included in the genesis file called a `gentx`: ```bash theme={null} # Create a gentx # NOTE: this command lets you set the number of coins. # Make sure this account has some coins with the genesis.app_state.staking.params.bond_denom denom hyperpaxd add-genesis-account my_validator 1000000000stake,10000000000ahpx ``` A `gentx` does three things: 1. Registers the `validator` account you created as a validator operator account (i.e. the account that controls the validator). 2. Self-delegates the provided `amount` of staking tokens. 3. Link the operator account with a Tendermint node pubkey that will be used for signing blocks. If no `--pubkey` flag is provided, it defaults to the local node pubkey created via the `hyperpaxd init` command above. For more information on `gentx`, use the following command: ```bash theme={null} hyperpaxd gentx --help ``` ### Collecting `gentx` By default, the genesis file do not contain any `gentxs`. A `gentx` is a transaction that bonds staking token present in the genesis file under `accounts` to a validator, essentially creating a validator at genesis. The chain will start as soon as more than 2/3rds of the validators (weighted by voting power) that are the recipient of a valid `gentx` come online after `genesis_time`. A `gentx` can be added manually to the genesis file, or via the following command: ```bash theme={null} # Add the gentx to the genesis file hyperpaxd collect-gentxs ``` This command will add all the `gentxs` stored in `~/.hyperpaxd/config/gentx` to the genesis file. ### Run Single Node Finally, check the correctness of the `genesis.json` file: ```bash theme={null} hyperpaxd validate-genesis ``` Now that everything is set up, you can finally start your node: ```bash theme={null} hyperpaxd start ``` :::tip To check all the available customizable options when running the node, use the `--help` flag. ::: You should see blocks come in. The previous command allow you to run a single node. This is enough for the next section on interacting with this node, but you may wish to run multiple nodes at the same time, and see how consensus happens between them. You can then stop the node using `Ctrl+C`. ## Further Configuration ### Key Management To run a node with the same key every time: replace `hyperpaxd keys add $KEY` in `./local_node.sh` with: ```bash theme={null} echo "your mnemonic here" | hyperpaxd keys add $KEY --recover ``` :::tip HyperPaxeer currently only supports 24 word mnemonics. ::: You can generate a new key/mnemonic with: ```bash theme={null} hyperpaxd keys add $KEY ``` To export your HyperPaxeer key as an Ethereum private key (for use with [Metamask](https://academy.evmosd.org/articles/beginner/connect-your-wallet/metamask) for example): ```bash theme={null} hyperpaxd keys unsafe-export-eth-key $KEY ``` For more about the available key commands, use the `--help` flag ```bash theme={null} hyperpaxd keys -h ``` ### Keyring backend options The instructions above include commands to use `test` as the `keyring-backend`. This is an unsecured keyring that doesn't require entering a password and should not be used in production. Otherwise, HyperPaxeer supports using a file or OS keyring backend for key storage. To create and use a file stored key instead of defaulting to the OS keyring, add the flag `--keyring-backend file` to any relevant command and the password prompt will occur through the command line. This can also be saved as a CLI config option with: ```bash theme={null} hyperpaxd config keyring-backend file ``` :::tip For more information about the Keyring and its backend options, click [here](./../concepts/keyring). ::: ### Enable Tracing To enable tracing when running the node, modify the last line of the `local_node.sh` script to be the following command, where: * `$TRACER` is the EVM tracer type to collect execution traces from the EVM transaction execution (eg. `json|struct|access_list|markdown`) * `$TRACESTORE` is the output file which contains KVStore tracing (eg. `store.txt`) ```bash theme={null} hyperpaxd start --evm.tracer $TRACER --tracestore $TRACESTORE --pruning=nothing $TRACE --log_level $LOGLEVEL --minimum-gas-prices=0.0001ahpx --json-rpc.api eth,txpool,personal,net,debug,web3 ``` ## Clearing data from chain ### Reset Data Alternatively, you can **reset** the blockchain database, remove the node's address book files, and reset the `priv_validator.json` to the genesis state. :::danger If you are running a **validator node**, always be careful when doing `hyperpaxd unsafe-reset-all`. You should never use this command if you are not switching `chain-id`. ::: :::danger **IMPORTANT**: Make sure that every node has a unique `priv_validator.json`. **Do not** copy the `priv_validator.json` from an old node to multiple new nodes. Running two nodes with the same `priv_validator.json` will cause you to double sign! ::: First, remove the outdated files and reset the data. ```bash theme={null} rm $HOME/.hyperpaxd/config/addrbook.json $HOME/.hyperpaxd/config/genesis.json hyperpaxd tendermint unsafe-reset-all --home $HOME/.hyperpaxd ``` Your node is now in a pristine state while keeping the original `priv_validator.json` and `config.toml`. If you had any sentry nodes or full nodes setup before, your node will still try to connect to them, but may fail if they haven't also been upgraded. ### Delete Data Data for the `hyperpaxd` binary should be stored at `~/.hyperpaxd`, respectively by default. To **delete** the existing binaries and configuration, run: ```bash theme={null} rm -rf ~/.hyperpaxd ``` To clear all data except key storage (if keyring backend chosen) and then you can rerun the full node installation commands from above to start the node again. ## Recording Transactions Per Second (TPS) In order to get a progressive value of the transactions per second, we use Prometheus to return the values. The Prometheus exporter runs at address `http://localhost:8877` so please add this section to your [Prometheus installation](https://opencensus.io/codelabs/prometheus/#1) config.yaml file like this ```yaml theme={null} global: scrape_interval: 10s external_labels: monitor: 'HyperPaxeer' scrape_configs: - job_name: 'HyperPaxeer' scrape_interval: 10s static_configs: - targets: ['localhost:8877'] ``` and then run Prometheus like this ```shell theme={null} prometheus --config.file=prom_config.yaml ``` and then visit the Prometheus dashboard at [http://localhost:9090/](http://localhost:9090/) then navigate to the expression area and enter the following expression ```shell theme={null} rate(hyperpaxd_transactions_processed[1m]) ``` which will show the rate of transactions processed. :::tip HyperPaxeer currently only supports 24 word mnemonics. ::: # Accounts Source: https://sidiorresearchlabs.mintlify.app/protocol/concepts/accounts # Accounts Crypto Wallets (or Accounts) can be created and represented in unique ways on different blockchains. For developers who interface with account types on HyperPaxeer, e.g. during wallet integration on their dApp frontend, it is therefore important to understand that accounts on HyperPaxeer are implemented to be compatible with Ethereum type addresses. ## Prerequisite Readings * [Cosmos SDK Accounts](https://docs.cosmos.network/main/learn/beginner/accounts) * [Ethereum Accounts](https://ethereum.org/en/whitepaper/#ethereum-accounts) ## Creating Accounts To create one account you can either create a private key, a keystore file (a private key protected by a password), or a mnemonic phrase (a string of words that can access multiple private keys). Aside from having different security features, the biggest difference between each of these is that a private key or keystore file only creates one account. Creating a mnemonic phrase gives you control of many accounts, all accessible with that same phrase. Cosmos blockchains, like HyperPaxeer, support creating accounts with mnemonic phrases, otherwise known as [hierarchical deterministic key generation](https://github.com/confio/cosmos-hd-key-derivation-spec) (HD keys). This allows the user to create accounts on multiple blockchains without having to manage multiple secrets. HD keys generate addresses by taking the mnemonic phrase and combining it with a piece of information called a [derivation path](https://learnmeabitcoin.com/technical/derivation-paths). Blockchains can differ in which derivation path they support. To access all accounts from an mnemonic phrase on a blockchain, it is therefore important to use that blockchain's specific derivation path. ## Representing Accounts The terms "account" and "address" are often used interchangeably to describe crypto wallets. In the Cosmos SDK, an account designates a pair of public key (PubKey) and private key (PrivKey). The derivation path defines what the private key, public key, and address would be. The PubKey can be derived to generate various addresses in different formats, which are used to identify users (among other parties) in the application. A common address form for Cosmos chains is the bech32 format (e.g. `HyperPaxeer1...`). Addresses are also associated with messages to identify the sender of the message. The PrivKey is used to generate digital signatures to prove that an address associated with the PrivKey approved of a given message. The proof is performed by applying a cryptographic scheme to the PrivKey, known as Elliptic Curve Digital Signature Algorithm (ECDSA), to generate a PubKey that is compared with the address in the message. ## HyperPaxeer Accounts HyperPaxeer defines its own custom `Account` type to implement a HD wallet that is compatible with Ethereum type addresses. It uses Ethereum's ECDSA secp256k1 curve for keys (`eth_secp265k1`) and satisfies the [EIP84](https://github.com/ethereum/EIPs/issues/84) for full [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) paths. This cryptographic curve is not to be confused with [Bitcoin's ECDSA secp256k1](https://en.bitcoin.it/wiki/Secp256k1) curve. The root HD path for HyperPaxeer-based accounts is `m/44'/60'/0'/0`. HyperPaxeer uses the Coin type `60` to support Ethereum type accounts, unlike many other Cosmos chains that use Coin type `118` ([list of coin types](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) The custom HyperPaxeer [EthAccount](https://github.com/Paxeer-Network/Paxeer-Network/blob/main/types/account.go#L28-L33) satisfies the `AccountI` interface from the Cosmos SDK auth module and includes additional fields that are required for Ethereum type addresses: ```go theme={null} // EthAccountI represents the interface of an EVM compatible account type EthAccountI interface { authtypes.AccountI // EthAddress returns the ethereum Address representation of the AccAddress EthAddress() common.Address // CodeHash is the keccak256 hash of the contract code (if any) GetCodeHash() common.Hash // SetCodeHash sets the code hash to the account fields SetCodeHash(code common.Hash) error // Type returns the type of Ethereum Account (EOA or Contract) Type() int8 } ``` For more information on Ethereum accounts head over to the [x/evm module](../modules/evm.md#concepts). ### Addresses and Public Keys [BIP-0173](https://github.com/satoshilabs/slips/blob/master/slip-0173.md) defines a new format for segregated witness output addresses that contains a human-readable part that identifies the Bech32 usage. HyperPaxeer uses the following HRP (human readable prefix) as the base HRP: | Network | Mainnet | Testnet | | ----------- | ------- | ------- | | HyperPaxeer | `pax` | `pax` | There are 3 main types of HRP for the `Addresses`/`PubKeys` available by default on HyperPaxeer (bech32 prefix: `pax`): * Addresses and Keys for **accounts**, which identify users (e.g. the sender of a `message`). They are derived using the **`eth_secp256k1`** curve. * Addresses and Keys for **validator operators**, which identify the operators of validators. They are derived using the **`eth_secp256k1`** curve. * Addresses and Keys for **consensus nodes**, which identify the validator nodes participating in consensus. They are derived using the **`ed25519`** curve. | | Address bech32 Prefix | Pubkey bech32 Prefix | Curve | Address byte length | Pubkey byte length | | ------------------ | --------------------- | -------------------- | --------------- | ------------------- | ------------------ | | Accounts | `pax` | `paxpub` | `eth_secp256k1` | `20` | `33` (compressed) | | Validator Operator | `paxvaloper` | `paxvaloperpub` | `eth_secp256k1` | `20` | `33` (compressed) | | Consensus Nodes | `paxvalcons` | `paxvalconspub` | `ed25519` | `20` | `32` | ### Address formats for clients `EthAccount` can be represented in both [Bech32](https://en.bitcoin.it/wiki/Bech32) (`pax1...`) and hex (`0x...`) formats for Ethereum's Web3 tooling compatibility. The Bech32 format is the default format for Cosmos-SDK queries and transactions through CLI and REST clients. The hex format on the other hand, is the Ethereum `common.Address` representation of a Cosmos `sdk.AccAddress`. * **Address (Bech32)**: `pax1z3t55m0l9h0eupuz3dp5t5cypyv674jj7mz2jw` * **Address ([EIP55](https://eips.ethereum.org/EIPS/eip-55) Hex)**: `0x91defC7fE5603DFA8CC9B655cF5772459BF10c6f` * **Compressed Public Key**: `{"@type":"/hyperpaxeer.crypto.v1.ethsecp256k1.PubKey","key":"AsV5oddeB+hkByIJo/4lZiVUgXTzNfBPKC73cZ4K1YD2"}` ### Address conversion The `hyperpaxd debug addr
` can be used to convert an address between hex and bech32 formats. For example: ```bash title="Bech32" theme={null} $ hyperpaxd debug addr pax1z3t55m0l9h0eupuz3dp5t5cypyv674jj7mz2jw Address: [20 87 74 109 255 45 223 158 7 130 139 67 69 211 4 9 25 175 86 82] Address (hex): 14574A6DFF2DDF9E07828B4345D3040919AF5652 Bech32 Acc: pax1z3t55m0l9h0eupuz3dp5t5cypyv674jj7mz2jw Bech32 Val: paxvaloper1z3t55m0l9h0eupuz3dp5t5cypyv674jjn4d6nn ``` ```bash title="Hex" theme={null} $ hyperpaxd debug addr 14574A6DFF2DDF9E07828B4345D3040919AF5652 Address: [20 87 74 109 255 45 223 158 7 130 139 67 69 211 4 9 25 175 86 82] Address (hex): 14574A6DFF2DDF9E07828B4345D3040919AF5652 Bech32 Acc: pax1z3t55m0l9h0eupuz3dp5t5cypyv674jj7mz2jw Bech32 Val: paxvaloper1z3t55m0l9h0eupuz3dp5t5cypyv674jjn4d6nn ``` ### Key output :::tip The Cosmos SDK Keyring output (i.e `hyperpaxd keys`) only supports addresses and public keys in Bech32 format. ::: We can use the `keys show` command of `hyperpaxd` with the flag `--bech (acc|val|cons)` to obtain the addresses and keys as mentioned above, ```bash title="Accounts" theme={null} $ hyperpaxd keys show dev0 --bech acc - name: dev0 type: local address: pax1z3t55m0l9h0eupuz3dp5t5cypyv674jj7mz2jw pubkey: '{"@type":"/hyperpaxeer.crypto.v1.ethsecp256k1.PubKey","key":"AsV5oddeB+hkByIJo/4lZiVUgXTzNfBPKC73cZ4K1YD2"}' mnemonic: "" ``` ```bash title="Validator" theme={null} $ hyperpaxd keys show dev0 --bech val - name: dev0 type: local address: paxvaloper1z3t55m0l9h0eupuz3dp5t5cypyv674jjn4d6nn pubkey: '{"@type":"/hyperpaxeer.crypto.v1.ethsecp256k1.PubKey","key":"AsV5oddeB+hkByIJo/4lZiVUgXTzNfBPKC73cZ4K1YD2"}' mnemonic: "" ``` ```bash title="Consensus" theme={null} $ hyperpaxd keys show dev0 --bech cons - name: dev0 type: local address: paxvalcons1rllqa5d97n6zyjhy6cnscc7zu30zjn3f7wyj2n pubkey: '{"@type":"/hyperpaxeer.crypto.v1.ethsecp256k1.PubKey","key":"A/fVLgIqiLykFQxum96JkSOoTemrXD0tFaFQ1B0cpB2c"}' mnemonic: "" ``` ## Querying an Account You can query an account address using the CLI, gRPC or ### Command Line Interface ```bash theme={null} # NOTE: the --output (-o) flag will define the output format in JSON or YAML (text) hyperpaxd q auth account $(hyperpaxd keys show dev0 -a) -o text '@type': /hyperpaxeer.types.v1.EthAccount base_account: account_number: "0" address: pax1z3t55m0l9h0eupuz3dp5t5cypyv674jj7mz2jw pub_key: '@type': /hyperpaxeer.crypto.v1.ethsecp256k1.PubKey key: AsV5oddeB+hkByIJo/4lZiVUgXTzNfBPKC73cZ4K1YD2 sequence: "1" code_hash: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 ``` ### Cosmos gRPC and REST ```bash theme={null} # GET /cosmos/auth/v1beta1/accounts/{address} curl -X GET "http://localhost:10337/cosmos/auth/v1beta1/accounts/Paxeer-Network14au322k9munkmx5wrchz9q30juf5wjgz2cfqku" -H "accept: application/json" ``` ### JSON-RPC To retrieve the Ethereum hex address using Web3, use the JSON-RPC [`eth_accounts`](./../../develop/api/ethereum-json-rpc/methods#eth-accounts) or [`personal_listAccounts`](./../../develop/api/ethereum-json-rpc/methods#personal-listAccounts) endpoints: ```bash theme={null} # query against a local node curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545 curl -X POST --data '{"jsonrpc":"2.0","method":"personal_listAccounts","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545 ``` # Chain ID Source: https://sidiorresearchlabs.mintlify.app/protocol/concepts/chain-id # Chain ID A chain ID is a unique identifier that represents a blockchain network. We use it to distinguish different blockchain networks from each other and to ensure that transactions and messages are sent to the correct network. HyperPaxeer network follows the format of `identifier_EIP155-version` format. ## Official Chain IDs :::tip **NOTE**: The latest Chain ID (i.e highest Version Number) is the latest version of the software and mainnet. Also note, that the following upgrades technically did not require a Chain ID change: * `HyperPaxeer_9001-1` -> `HyperPaxeer_9001-2` * `hyperpax_125-3` -> `hyperpax_125-4` ::: ### Mainnet | Name | Chain ID | Identifier | EIP-155 Number | Version | Active | | ------------------- | ---------------- | ---------- | -------------- | ------- | ------ | | HyperPaxeer Mainnet | `hyperpax_125-1` | `hyperpax` | `125` | `1` | βœ… | **No public testnet available.** Developers should use local development networks. See the [Single Node](../cli/single-node) guide for setting up a local development environment. :::tip You can also look up the [EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) `Chain ID` by referring to [chainlist.org](https://chainlist.org/). ::: ## The Chain Identifier Every chain must have a unique identifier or `chain-id`. Tendermint requires each application to define its own `chain-id` in the [genesis.json fields](https://docs.tendermint.com/master/spec/core/genesis.html#genesis-fields). However, to comply with both EIP-155 and Cosmos standard for chain upgrades, HyperPaxeer-compatible chains must implement a special structure for their chain identifiers. ## Structure The HyperPaxeer Chain ID contains 3 main components * **Identifier**: Unstructured string that defines the name of the application. * **EIP-155 Number**: Immutable [EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) `CHAIN_ID` that defines the replay attack protection number. * **Version Number**: Is the version number (always positive) that the chain is currently running. This number **MUST** be incremented every time the chain is upgraded or forked to avoid network or consensus errors. ### Format The format for specifying and HyperPaxeer compatible chain-id in genesis is the following: ```bash theme={null} {identifier}_{EIP155}-{version} ``` The following table provides an example where the second row corresponds to an upgrade from the first one: | ChainID | Identifier | EIP-155 Number | Version Number | | ---------------- | ----------- | -------------- | -------------- | | `hyperpax_125-1` | HyperPaxeer | 9000 | 1 | | `hyperpax_125-2` | HyperPaxeer | 9000 | 2 | | `...` | ... | ... | ... | | `hyperpax_125-N` | HyperPaxeer | 9000 | N | # Encoding Source: https://sidiorresearchlabs.mintlify.app/protocol/concepts/encoding # Encoding Encoding refers to the process of converting data from one format to another to make it more secure and efficient. In the context of blockchain, encoding is used to ensure that data is stored and transmitted in a way that is secure and easily accessible. The Recursive Length Prefix (RLP) is a serialization format used extensively in Ethereum's execution clients. Its purpose is to encode arbitrarily nested arrays of binary data, and it is the main encoding method used to serialize objects in Ethereum. RLP only encodes structure and leaves encoding specific atomic data types, such as strings, integers, and floats, to higher-order protocols. In Ethereum, integers must be represented in big-endian binary form with no leading zeroes, making the integer value zero equivalent to the empty byte array. The RLP encoding function takes in an item, which is defined as a single byte whose value is in the \[0x00, 0x7f] range or a string of 0-55 bytes long. If the string is more than 55 bytes long, the RLP encoding consists of a single byte with value 0xb7 (dec. 183) plus the length in bytes of the length of the string in binary form, followed by the length of the string, followed by the string. RLP is used for hash verification, where a transaction is signed by signing the RLP hash of the transaction data, and blocks are identified by the RLP hash of their header. RLP is also used for encoding data over the wire and for some cases where there should be support for efficient encoding of the merkle tree data structure. The Ethereum execution layer uses RLP as the primary encoding method to serialize objects, but the newer Simple Serialize (SSZ) replaces RLP as the encoding for the new consensus layer in Ethereum 2.0. The Cosmos Stargate release introduces protobuf as the main encoding format for both client and state serialization. All the EVM module types that are used for state and clients, such as transaction messages, genesis, query services, etc., will be implemented as protocol buffer messages. The Cosmos SDK also supports the legacy Amino encoding. Protocol Buffers (protobuf) is a language-agnostic binary serialization format that is smaller and faster than JSON. It is used to serialize structured data, such as messages, and is designed to be highly efficient and extensible. The encoding format is defined in a language-agnostic language called Protocol Buffers Language (proto3), and the encoded messages can be used to generate code for a variety of programming languages. The main advantage of protobuf is its efficiency, which results in smaller message sizes and faster serialization and deserialization times. The RLP decoding process is as follows: according to the first byte (i.e., prefix) of input data and decoding the data type, the length of the actual data and offset; according to the type and offset of data, decode the data correspondingly. ## Prerequisite Readings * [Cosmos SDK Encoding](https://docs.cosmos.network/main/learn/advanced/encoding) * [Ethereum RLP](https://eth.wiki/en/fundamentals/rlp) ## Encoding Formats ### Protocol Buffers The Cosmos [Stargate](https://stargate.cosmos.network/) release introduces [protobuf](https://developers.google.com/protocol-buffers) as the main encoding format for both client and state serialization. All the EVM module types that are used for state and clients (transaction messages, genesis, query services, etc) will be implemented as protocol buffer messages. ### Amino The Cosmos SDK also supports the legacy Amino encoding format for backwards compatibility with previous versions, specially for client encoding and signing with Ledger devices. HyperPaxeer does not support Amino in the EVM module, but it is supported for all other Cosmos SDK modules that enable it. ### RLP Recursive Length Prefix ([RLP](https://eth.wiki/en/fundamentals/rlp)), is an encoding/decoding algorithm that serializes a message and allows for quick reconstruction of encoded data. HyperPaxeer uses RLP to encode/decode Ethereum messages for JSON-RPC handling to conform messages to the proper Ethereum format. This allows messages to be encoded and decoded in the exact format as Ethereum's. The `x/evm` transactions (`MsgEthereumTx`) encoding is performed by casting the message to a go-ethereum's `Transaction` and then marshaling the transaction data using RLP: ```go theme={null} // TxEncoder overwrites sdk.TxEncoder to support MsgEthereumTx func (g txConfig) TxEncoder() sdk.TxEncoder { return func(tx sdk.Tx) ([]byte, error) { msg, ok := tx.(*evmtypes.MsgEthereumTx) if ok { return msg.AsTransaction().MarshalBinary() } return g.TxConfig.TxEncoder()(tx) } } // TxDecoder overwrites sdk.TxDecoder to support MsgEthereumTx func (g txConfig) TxDecoder() sdk.TxDecoder { return func(txBytes []byte) (sdk.Tx, error) { tx := ðtypes.Transaction{} err := tx.UnmarshalBinary(txBytes) if err == nil { msg := &evmtypes.MsgEthereumTx{} msg.FromEthereumTx(tx) return msg, nil } return g.TxConfig.TxDecoder()(txBytes) } } ``` # Gas and fees Source: https://sidiorresearchlabs.mintlify.app/protocol/concepts/gas-and-fees # Gas and Fees Users need to pay a fee to submit transactions on the HyperPaxeer network. As fees are handled differently on Ethereum and Cosmos, it is important to understand how the HyperPaxeer blockchain implements an Ethereum-type fee calculation, that is compatible with the Cosmos SDK. Therefore this overview explains the basics of gas calculation, how to provide fees for transactions and how the Ethereum-type fee calculation uses a fee market (EIP-1559) for prioritizing transactions. ## Prerequisite Readings * [Cosmos SDK Gas](https://docs.cosmos.network/main/learn/beginner/gas-fees.html) * [Ethereum Gas](https://ethereum.org/en/developers/docs/gas/) ## Basics ### Why do Transactions Need Fees? If anyone can submit transactions to a network at no cost, the network can be overrun by a handful of actors sending large numbers of fraudulent transactions to clog up the network and stop it from working. The solution to this is a concept called β€œgas," which is a resource consumed throughout transaction execution. In practice, a small amount of gas is spent on each step of code execution, thus effectively charging for use of a validator’s resources and preventing malicious actors from halting a network at will. ### What is Gas? In general, gas is a unit that measures the computational intensity of a particular transaction β€” in other words, how much work would be required to evaluate and perform the job. Complex, multi-step transactions, such as a Cosmos transaction that delegates to a dozen validators, require more gas than simple, single-step transactions, such as a Cosmos transaction to send tokens to another address. When referring to a transaction, β€œgas” refers to the total quantity of gas required for the transaction. For example, a transaction may require 300,000 units of gas to be executed. Gas can be thought of as electricity (kWh) within a house or factory, or fuel for automobiles. The idea is that it costs something to get somewhere. More on Gas: * [Cosmos Gas Fees](https://docs.cosmos.network/main/learn/beginner/gas-fees) * [Cosmos Tx Lifecycle](https://docs.cosmos.network/main/learn/beginner/tx-lifecycle.html) * [Ethereum Gas](https://ethereum.org/en/developers/docs/gas/) ### How is Gas Calculated? In general, there’s no way to know exactly how much gas a transaction will cost without simply running it. Using the Cosmos SDK, this can be done by [simulating the Tx](https://docs.cosmos.network/main/run-node/txs#simulating-a-transaction). Otherwise, there are ways to estimate the amount of gas a transaction will require, based on the details of the transaction fields, and data. In the case of the EVM, for example, each bytecode operation has a [corresponding amount of gas](https://ethereum.org/en/developers/docs/evm/opcodes/). More on Gas Calculations: * [Estimate Gas](https://docs.ethers.org/v5/api/providers/provider/#Provider-estimateGas) * [Executing EVM Bytecode](https://ethereum.org/en/developers/docs/evm/opcodes/) * [Simulate a Cosmos SDK Tx](https://docs.cosmos.network/main/run-node/txs#simulating-a-transaction) ### How does Gas Relate to Fees? While gas refers to the computational work required for execution, fees refer to the amount of the tokens you actually spend to execute the transaction. They are derived using the following formula: ```markdown theme={null} Total Fees = Gas * Gas Price (the price per unit of gas) ``` If β€œgas” was measured in kWh, the β€œgas price” would be the rate (in dollars per kWh) determined by your energy provider, and the β€œfees” would be your bill. Just as with electricity, gas price is liable to fluctuate over a given day, depending on network traffic. More on Gas vs. Fees: * [Cosmos Gas and Fees](https://docs.cosmos.network/main/learn/beginner/gas-fees) * [Ethereum Gas and Fees](https://ethereum.org/en/developers/docs/gas/) ### How are Fees Handled on Cosmos? Gas fees on Cosmos are relatively straightforward. As a user, you specify two fields: 1. A `GasLimit` corresponding to an upper bound on execution gas, defined as `GasWanted` 2. One of `Fees` or `GasPrice`, which will be used to specify or calculate the transaction fees The node will entirely consume the fees provided, then begin to execute the transaction. If the `GasLimit` is found to be insufficient during execution, the transaction will fail and roll back any changes made, without refunding the fees provided. Validators for Cosmos SDK-based chains can specify their `min-gas-prices` that they will enforce when selecting transactions to include in blocks. Thus, transactions with insufficient fees will encounter delays or fail outright. At the beginning of each block, fees from the previous block are [allocated to validators and delegators](https://docs.cosmos.network/main/modules/distribution), after which they can be withdrawn and spent. ### How are Fees Handled on Ethereum? Fees on Ethereum include multiple implementations that were introduced over time. Originally, a user would specify a `GasPrice` and `GasLimit` within a transactionβ€”much like a Cosmos SDK transaction. A block proposer would receive the entire gas fee from each transaction in the block, and they would select transactions to include accordingly. With proposal EIP-1559 and the London Hard fork, gas calculation changed. The `GasPrice` from above has now been split into two separate components: a `BaseFee` and `PriorityFee`. The `BaseFee` is calculated automatically based on the block size and is burned once the block is mined. The `PriorityFee` goes to the proposer and represents a tip, or an incentive for a proposer to include the transaction in a block. ```markdown theme={null} Gas Price = Base Fee + Priority Fee ``` Within a transaction, users can specify a `max_fee_per_gas` corresponding to the total `GasPrice` and a `max_priority_fee_per_gas` corresponding to a maximum `PriorityFee`, in addition to specifying the `gas_limit` as before. All surplus gas that was not required for execution is refunded to the user. More on Ethereum Fees: * [Gas Calculation Docs](https://ethereum.org/en/developers/docs/gas/) * [Proposal EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) ## Implementation ### How are Gas and Fees Handled on HyperPaxeer? Fundamentally, HyperPaxeer is a Cosmos SDK chain that enables EVM compatibility as part of a Cosmos SDK module. As a result of this architecture, all EVM transactions are ultimately encoded as Cosmos SDK transactions and update a Cosmos SDK-managed state. Since all transactions are represented as Cosmos SDK transactions, transaction fees can be treated identically across execution layers. In practice, dealing with fees includes standard Cosmos SDK logic, some Ethereum logic, and custom HyperPaxeer logic. For the most part, fees are collected by the `fee_collector` module, then paid out to validators and delegators. A few key distinctions are as follows: 1. Fee Market Module In order to support EIP-1559 gas and fee calculation on HyperPaxeer’ EVM layer, HyperPaxeer tracks the gas supplied for each block and uses that to calculate a base fee for future EVM transactions, thus enabling EVM dynamic fees and transaction prioritization as specified by EIP-1559. For EVM transactions, each node bypasses their local `min-gas-prices` configuration, and instead applies EIP-1559 fee logicβ€”the gas price simply must be greater than both the global `min-gas-price` and the block's `BaseFee`, and the surplus is considered a priority tip. This allows validators to compute Ethereum fees without applying Cosmos SDK fee logic. Unlike on Ethereum, the `BaseFee` on HyperPaxeer is not burned, and instead is distributed to validators and delegators. Furthermore, the `BaseFee` is lower-bounded by the global `min-gas-price` (currently, the global `min-gas-price` parameter is set to zero, although it can be updated via Governance). 2. EVM Gas Refunds HyperPaxeer refunds a fraction (at least 50% by default) of the unused gas for EVM transactions to approximate the current behavior on Ethereum. [Why not always 100%?](https://github.com/paxeer-network/hyperpaxeer/issues/1085) ### Detailed Timeline 1. Nodes execute the previous block and run the `EndBlock` hook * As part of this hook, the FeeMarket (EIP-1559) module tracks the total `TransientGasWanted` from the transactions on this block. This will be used for the next block’s `BaseFee`. 2. Nodes receive transactions for a subsequent block and gossip these transactions to peers * These can be sorted and prioritized by the included fee price (using EIP-1559 fee priority mechanics for EVM transactions - [code snippet](https://github.com/paxeer-network/hyperpaxeer/blob/57ed355c985d9f3116aba6aabfa2ee0f3f38e966/app/ante/eth.go#L137)), to be included in the next block 3. Nodes run `BeginBlock` for the subsequent block * The FeeMarket module calculates the `BaseFee` ([code snippet](https://github.com/paxeer-network/hyperpaxeer/blob/89fdd1984826ea524cb9b8feb089a99b6cfe8ace/x/feemarket/keeper/abci.go#L14)) to be applied for this block using the total `GasWanted` from the previous block. * The Distribution module [distributes](https://docs.cosmos.network/main/modules/distribution#begin-block) the previous block’s fee rewards to validators and delegators 4. For each valid transaction that will be included in this block, nodes perform the following: * They run an `AnteHandler` corresponding to the transaction type. This process: 1. Performs basic transaction validation 2. Verifies the fees provided are greater than the global and local minimum validator values *and* greater than the `BaseFee` calculated 3. (For Ethereum transactions) Preemptively consumes gas for the EVM transaction 4. Deducts the transaction fees from the user and transfers them to the `fee_collector` module 5. Increments the `TransientGasWanted` in the current block, to be used to calculate the next block’s `BaseFee` * Then, for standard Cosmos Transactions, nodes: 1. Execute the transaction and update the state 2. Consume gas for the transaction * For Ethereum Transactions, nodes: 1. Execute the transaction and update the state 2. Calculate the gas used and compare it to the gas supplied, then refund a designated portion of the surplus 5. Nodes run `EndBlock` for this block and store the block’s `GasWanted` ## Detailed Mechanics ### Cosmos `Gas` In the Cosmos SDK, gas is tracked in the main `GasMeter` and the `BlockGasMeter`: * `GasMeter`: keeps track of the gas consumed during executions that lead to state transitions. It is reset on every transaction execution. * `BlockGasMeter`: keeps track of the gas consumed in a block and enforces that the gas does not go over a predefined limit. This limit is defined in the Tendermint consensus parameters and can be changed via governance parameter change proposals. Since gas is priced per-byte, the same interaction is more gas-intensive with larger parameter values than smaller (unlike Ethereum's `uint256` values, Cosmos SDK numericals are represented using [Big.Int](https://pkg.go.dev/math/big#Int) types, which are dynamically sized). More information regarding gas as part of the Cosmos SDK can be found [here](https://docs.cosmos.network/main/learn/beginner/gas-fees.html). ### Matching EVM Gas consumption HyperPaxeer is an EVM-compatible chain that supports Ethereum Web3 tooling. For this reason, gas consumption must be equatable with other EVMs, most importantly Ethereum. The main difference between EVM and Cosmos state transitions, is that the EVM uses a [gas table](https://github.com/ethereum/go-ethereum/blob/master/params/protocol_params.go) for each OPCODE, whereas Cosmos uses a `GasConfig` that charges gas for each CRUD operation by setting a flat and per-byte cost for accessing the database. \+++ [https://github.com/cosmos/cosmos-sdk/blob/3fd376bd5659f076a4dc79b644573299fd1ec1bf/store/types/gas.go#L187-L196](https://github.com/cosmos/cosmos-sdk/blob/3fd376bd5659f076a4dc79b644573299fd1ec1bf/store/types/gas.go#L187-L196) In order to match the gas consumed by the EVM, the gas consumption logic from the SDK is ignored, and instead the gas consumed is calculated by subtracting the state transition leftover gas plus refund from the gas limit defined on the message. To ignore the SDK gas consumption, we reset the transaction `GasMeter` count to 0 and manually set it to the `gasUsed` value computed by the EVM module at the end of the execution. \+++ [https://github.com/paxeer-network/hyperpaxeer/blob/098da6d0cc0e0c4cefbddf632df1057383973e4a/x/evm/keeper/state\_transition.go#L188](https://github.com/paxeer-network/hyperpaxeer/blob/098da6d0cc0e0c4cefbddf632df1057383973e4a/x/evm/keeper/state_transition.go#L188) ### `AnteHandler` The Cosmos SDK [`AnteHandler`](https://docs.cosmos.network/main/learn/beginner/gas-fees.html#antehandler) performs basic checks prior to transaction execution. These checks are usually signature verification, transaction field validation, transaction fees, etc. Regarding gas consumption and fees, the `AnteHandler` checks that the user has enough balance to cover for the tx cost (amount plus fees) as well as checking that the gas limit defined in the message is greater or equal than the computed intrinsic gas for the message. ### Gas Refunds In the EVM, gas can be specified prior to execution. The totality of the gas specified is consumed at the beginning of the execution (during the `AnteHandler` step) and the remaining gas is refunded back to the user if any gas is left over after the execution. Additionally the EVM can also define gas to be refunded back to the user but those will be capped to a fraction of the used gas depending on the fork/version being used. ### Zero-Fee Transactions In Cosmos, a minimum gas price is not enforced by the `AnteHandler` as the `min-gas-prices` is checked against the local node/validator. In other words, the minimum fees accepted are determined by the validators of the network, and each validator can specify a different minimum value for their fees. This potentially allows end users to submit 0 fee transactions if there is at least one single validator that is willing to include transactions with `0` gas price in their blocks proposed. For this same reason, in HyperPaxeer it is possible to send transactions with `0` fees for transaction types other than the ones defined by the `evm` module. EVM module transactions cannot have `0` fees as gas is required inherently by the EVM. This check is done by the EVM transactions stateless validation (i.e `ValidateBasic`) function as well as on the custom `AnteHandler` defined by HyperPaxeer. ### Gas Estimation Ethereum provides a JSON-RPC endpoint `eth_estimateGas` to help users set up a correct gas limit in their transactions. For that reason, a specific query API `EstimateGas` is implemented in HyperPaxeer. It will apply the transaction against the current block/state and perform a binary search in order to find the optimal gas value to return to the user (the same transaction will be applied over and over until we find the minimum gas needed before it fails). The reason we need to use a binary search is that the gas required for the transaction might be higher than the value returned by the EVM after applying the transaction, so we need to try until we find the optimal value. A cache context will be used during the whole execution to avoid changes be persisted in the state. \+++ [https://github.com/paxeer-network/hyperpaxeer/blob/098da6d0cc0e0c4cefbddf632df1057383973e4a/x/evm/keeper/grpc\_query.go#L100](https://github.com/paxeer-network/hyperpaxeer/blob/098da6d0cc0e0c4cefbddf632df1057383973e4a/x/evm/keeper/grpc_query.go#L100) For Cosmos Tx's, developers can use Cosmos SDK's [transaction simulation](https://docs.cosmos.network/main/run-node/txs#simulating-a-transaction) to create an accurate estimate. ### Cross-Chain Gas and Fees Let’s say a user transfers tokens from Chain A to HyperPaxeer via IBC-transfer and wants to execute an HyperPaxeer transactionβ€”however, they don’t have any HyperPaxeer tokens to cover fees. The Cosmos SDK introduced `Tips` as a solution to this issue; a user can cover fees using a different tokenβ€”in this case, tokens from Chain A. To cover transaction fees using a tip, this user can sign a transaction with a tip and no fees, then send the transaction to a fee relayer. The fee relayer will then cover the fee in the native currency (HyperPaxeer in this case), and receive the tip in payment, behaving as an intermediary exchange. ## Dealing with gas and fees with the HyperPaxeer CLI When broadcasting a transaction using the HyperPaxeer CLI client, users should keep into consideration the options available. There are three flags to consider when sending a transaction to the network: * `--fees`: fees to pay along with transaction; eg: 10ahpx. Defaults to the required fees. * `--gas`: the gas limit to set per-transaction; the default value is 200000. * `--gas-prices`: gas prices to determine the transaction fee (e.g. 10ahpx). However, not all of them need to be defined on each transaction. The correct combinations are: * `--fees=auto`: estimates fees and gas automatically (same behavior as `--gas=auto`). Throws an error if using any other fees-related flag (e.i, `--gas-prices` , `--fees`) * `--gas=auto`: same behavior as `--fees=auto`. Throws an error if using any other fees-related flag (e.i, `--gas-prices` , `--fees`) * `--gas={int}`: uses the specified gas amount and the required fees for the transaction * `--fees={int}{denom}`: uses the specified fees for the tx. Uses gas default value (200000) for the tx. * `--fees={int}{denom} --gas={int}`: uses specified gas and fees. Calculates gas-prices with the provided params * `--gas-prices={int}{denom}`: uses the provided gas price and the default gas amount (200000) * `--gas-prices={int}{denom} --gas={int}`: uses the gas specified on for the tx and calculates the fee with the corresponding parameters. The reader should note that the former two options provide a frendlier user experience for new users, and the latter are for more advanced users, who desire more control over these parameters. The team introduced the `auto` flag option that calculates automatically the gas and fees required to execute a transaction. In this way, new users or developers can perform transactions without the hustle of defining specific gas and fees values. Using the `auto` flag sometimes may fail on estimating the right gas and fees based on network traffic. To overcome this, you can use a higher value for the `--gas-adjustment` flag. By default, this is set to `1.2`. When the estimated values are insufficient, retry with a higher gas adjustment, for example, `--gas-adjustment 1.3`. It is not possible to use the `--gas-prices` and `--fees` flags combined. If so, the user will get an error stating that cannot provide both fees and gas prices. Keep in mind that the above combinations may fail if the provided fees or gas amount is insufficient. If that is the case, the CLI will return an error message with the specific reason. For example: ```shell theme={null} raw_log: 'out of gas in location: submit proposal; gasWanted: 200000, gasUsed: 263940. Please retry with a gas (--gas flag) amount higher than gasUsed: out of gas' ``` # Keyring Source: https://sidiorresearchlabs.mintlify.app/protocol/concepts/keyring # Keyring Create, import, export and delete keys using the CLI keyring. The keyring holds the private/public keypairs used to interact with the node. For instance, a validator key needs to be set up before running the node, so that blocks can be correctly signed. The private key can be stored in different locations, called ["backends"](#keyring-backends), such as a file or the operating system's own key storage. :::tip In case, you need a refresher on private key and key management, please reference our [Key Management](./key-management). ::: ## Add keys You can use the following commands for help with the `keys` command and for more information about a particular subcommand, respectively: ```bash theme={null} hyperpaxd keys ``` ```bash theme={null} hyperpaxd keys [command] --help ``` To create a new key in the keyring, run the `add` subcommand with a `` argument. You will have to provide a password for the newly generated key. This key will be used in the next section. ```bash theme={null} hyperpaxd keys add dev0 # Put the generated address in a variable for later use. MY_VALIDATOR_ADDRESS=$(hyperpaxd keys show dev0 -a) ``` This command generates a new 24-word mnemonic phrase, persists it to the relevant backend, and outputs information about the keypair. If this keypair will be used to hold value-bearing tokens, be sure to write down the mnemonic phrase somewhere safe! By default, the keyring generates a `eth_secp256k1` key. The keyring also supports `ed25519` keys, which may be created by passing the `--algo` flag. A keyring can of course hold both types of keys simultaneously. :::tip **Note**: The Ethereum address associated with a public key can be derived by taking the full Ethereum public key of type `eth_secp256k1`, computing the `Keccak-256` hash, and truncating the first twelve bytes. ::: :::warning **NOTE**: Cosmos `secp256k1` keys are not supported on HyperPaxeer due to compatibility issues with Ethereum transactions. ::: ## Keyring Backends ### OS :::tip **`os`** is the default option since operating system's default credentials managers are designed to meet users' most common needs and provide them with a comfortable experience without compromising on security. ::: The `os` backend relies on operating system-specific defaults to handle key storage securely. Typically, an operating system's credential sub-system handles password prompts, private keys storage, and user sessions according to the user's password policies. Here is a list of the most popular operating systems and their respective passwords manager: * macOS (since Mac OS 8.6): [Keychain](https://support.apple.com/en-gb/guide/keychain-access/welcome/mac) * Windows: [Credentials Management API](https://docs.microsoft.com/en-us/windows/win32/secauthn/credentials-management) * GNU/Linux: * [libsecret](https://gitlab.gnome.org/GNOME/libsecret) * [kwallet](https://api.kde.org/frameworks/kwallet/html/index.html) GNU/Linux distributions that use GNOME as default desktop environment typically come with [Seahorse](https://wiki.gnome.org/Apps/Seahorse). Users of KDE based distributions are commonly provided with [KDE Wallet Manager](https://userbase.kde.org/KDE_Wallet_Manager). Whilst the former is in fact a `libsecret` convenient frontend, the latter is a `kwallet` client. The recommended backends for headless environments are `file` and `pass`. ### File The `file` stores the keyring encrypted within the app's configuration directory. This keyring will request a password each time it is accessed, which may occur multiple times in a single command resulting in repeated password prompts. If using bash scripts to execute commands using the `file` option you may want to utilize the following format for multiple prompts: ```bash theme={null} # assuming that KEYPASSWD is set in the environment yes $KEYPASSWD | hyperpaxd keys add me yes $KEYPASSWD | hyperpaxd keys show me # start hyperpaxd with keyring-backend flag hyperpaxd --keyring-backend=file start ``` :::tip The first time you add a key to an empty keyring, you will be prompted to type the password twice. ::: ### Password Store The `pass` backend uses the [pass](https://www.passwordstore.org/) utility to manage on-disk encryption of keys' sensitive data and metadata. Keys are stored inside `gpg` encrypted files within app-specific directories. `pass` is available for the most popular UNIX operating systems as well as GNU/Linux distributions. Please refer to its manual page for information on how to download and install it. :::tip **`pass`** uses [GnuPG](https://gnupg.org/) for encryption. `gpg` automatically invokes the `gpg-agent` daemon upon execution, which handles the caching of GnuPG credentials. Please refer to `gpg-agent` man page for more information on how to configure cache parameters such as credentials TTL and passphrase expiration. ::: The password store must be set up prior to first use: ```sh theme={null} pass init ``` Replace `` with your GPG key ID. You can use your personal GPG key or an alternative one you may want to use specifically to encrypt the password store. ### KDE Wallet Manager The `kwallet` backend uses `KDE Wallet Manager`, which comes installed by default on the GNU/Linux distributions that ships KDE as default desktop environment. Please refer to [KWallet Handbook](https://docs.kde.org/stable5/en/kwalletmanager/kwallet5/) for more information. ### Testing The `test` backend is a password-less variation of the `file` backend. Keys are stored **unencrypted** on disk. This keyring is provided for testing purposes only. Use at your own risk! :::danger 🚨 **DANGER**: Never create your mainnet validator keys using a `test` keying backend. Doing so might result in a loss of funds by making your funds remotely accessible via the `eth_sendTransaction` JSON-RPC endpoint. Ref: [Security Advisory: Insecurely configured geth can make funds remotely accessible](https://blog.ethereum.org/2015/08/29/security-alert-insecurely-configured-geth-can-make-funds-remotely-accessible/) ::: ### In Memory The `memory` backend stores keys in memory. The keys are immediately deleted after the program has exited. :::danger **IMPORTANT**: Provided for testing purposes only. The `memory` backend is **not** recommended for use in production environments. Use at your own risk! ::: # Multisig Source: https://sidiorresearchlabs.mintlify.app/protocol/concepts/multisig # Multisig Learn how to generate, sign and broadcast a transaction using the keyring multisig. A **multisig account** is an HyperPaxeer account with a special key that can require more than one signature to sign transactions. This can be useful for increasing the security of the account or for requiring the consent of multiple parties to make transactions. Multisig accounts can be created by specifying: * threshold number of signatures required * the public keys involved in signing To sign with a multisig account, the transaction must be signed individually by the different keys specified for the account. Then, the signatures will be combined into a multi-signature which can be used to sign the transaction. If fewer than the threshold number of signatures needed are present, the resultant multi-signature is considered invalid. ## Generate a Multisig key ```bash theme={null} hyperpaxd keys add --multisig=name1,name2,name3[...] --multisig-threshold=K new_key_name ``` `K` is the minimum number of private keys that must have signed the transactions that carry the public key's address as signer. The `--multisig` flag must contain the name of public keys that will be combined into a public key that will be generated and stored as `new_key_name` in the local database. All names supplied through `--multisig` must already exist in the local database. Unless the flag `--nosort` is set, the order in which the keys are supplied on the command line does not matter, i.e. the following commands generate two identical keys: ```bash theme={null} hyperpaxd keys add --multisig=p1,p2,p3 --multisig-threshold=2 multisig_address hyperpaxd keys add --multisig=p2,p3,p1 --multisig-threshold=2 multisig_address ``` Multisig addresses can also be generated on-the-fly and printed through the which command: ```bash theme={null} hyperpaxd keys show --multisig-threshold=K name1 name2 name3 [...] ``` ## Signing a transaction ### Step 1: Create the multisig key Let's assume that you have `test1` and `test2` want to make a multisig account with `test3`. First import the public keys of `test3` into your keyring. ```sh theme={null} hyperpaxd keys add \ test3 \ --pubkey=HyperPaxeerpub1addwnpepqgcxazmq6wgt2j4rdfumsfwla0zfk8e5sws3p3zg5dkm9007hmfysxas0u2 ``` Generate the multisig key with 2/3 threshold. ```sh theme={null} hyperpaxd keys add \ multi \ --multisig=test1,test2,test3 \ --multisig-threshold=2 ``` You can see its address and details: ```sh theme={null} hyperpaxd keys show multi - name: multi type: multi address: HyperPaxeer1e0fx0q9meawrcq7fmma9x60gk35lpr4xk3884m pubkey: HyperPaxeerpub1ytql0csgqgfzd666axrjzq3mxw59ys6yqcd3ydjvhgs0uzs6kdk5fp4t73gmkl8t6y02yfq7tvfzd666axrjzq3sd69kp5usk492x6nehqjal67ynv0nfqapzrzy3gmdk27la0kjfqfzd666axrjzq6utqt639ka2j3xkncgk65dup06t297ccljmxhvhu3rmk92u3afjuyz9dg9 mnemonic: "" threshold: 0 pubkeys: [] ``` Let's add 10 HyperPaxeer to the multisig wallet: ```bash theme={null} hyperpaxd tx bank send \ test1 \ HyperPaxeer1e0fx0q9meawrcq7fmma9x60gk35lpr4xk3884m \ 10000000000000000000ahpx \ --chain-id=hyperpax_125-4 \ --gas=auto \ --fees=1000000ahpx \ --broadcast-mode=block ``` ### Step 2: Create the multisig transaction We want to send 5 HyperPaxeer from our multisig account to `HyperPaxeer1rgjxswhuxhcrhmyxlval0qa70vxwvqn2e0srft`. ```bash theme={null} hyperpaxd tx bank send \ HyperPaxeer1rgjxswhuxhcrhmyxlval0qa70vxwvqn2e0srft \ HyperPaxeer157g6rn6t6k5rl0dl57zha2wx72t633axqyvvwq \ 5000000000000000000ahpx \ --gas=200000 \ --fees=1000000ahpx \ --chain-id=hyperpax_125-4 \ --generate-only > unsignedTx.json ``` The file `unsignedTx.json` contains the unsigned transaction encoded in JSON. ```json theme={null} { "body": { "messages": [ { "@type": "/cosmos.bank.v1beta1.MsgSend", "from_address": "HyperPaxeer1rgjxswhuxhcrhmyxlval0qa70vxwvqn2e0srft", "to_address": "HyperPaxeer157g6rn6t6k5rl0dl57zha2wx72t633axqyvvwq", "amount": [ { "denom": "ahpx", "amount": "5000000000000000000" } ] } ], "memo": "", "timeout_height": "0", "extension_options": [], "non_critical_extension_options": [] }, "auth_info": { "signer_infos": [], "fee": { "amount": [ { "denom": "ahpx", "amount": "1000000" } ], "gas_limit": "200000", "payer": "", "granter": "" } }, "signatures": [] } ``` ### Step 3: Sign individually Sign with `test1` and `test2` and create individual signatures. ```sh theme={null} hyperpaxd tx sign \ unsignedTx.json \ --multisig=HyperPaxeer1e0fx0q9meawrcq7fmma9x60gk35lpr4xk3884m \ --from=test1 \ --output-document=test1sig.json \ --chain-id=hyperpax_125-4 ``` ```sh theme={null} hyperpaxd tx sign \ unsignedTx.json \ --multisig=HyperPaxeer1e0fx0q9meawrcq7fmma9x60gk35lpr4xk3884m \ --from=test2 \ --output-document=test2sig.json \ --chain-id=hyperpax_125-4 ``` ### Step 4: Create multisignature Combine signatures to sign transaction. ```sh theme={null} hyperpaxd tx multisign \ unsignedTx.json \ multi \ test1sig.json test2sig.json \ --output-document=signedTx.json \ --chain-id=hyperpax_125-4 ``` The TX is now signed: ```json theme={null} { "body": { "messages": [ { "@type": "/cosmos.bank.v1beta1.MsgSend", "from_address": "HyperPaxeer1rgjxswhuxhcrhmyxlval0qa70vxwvqn2e0srft", "to_address": "HyperPaxeer157g6rn6t6k5rl0dl57zha2wx72t633axqyvvwq", "amount": [ { "denom": "ahpx", "amount": "5000000000000000000" } ] } ], "memo": "", "timeout_height": "0", "extension_options": [], "non_critical_extension_options": [] }, "auth_info": { "signer_infos": [ { "public_key": { "@type": "/cosmos.crypto.multisig.LegacyAminoPubKey", "threshold": 2, "public_keys": [ { "@type": "/cosmos.crypto.secp256k1.PubKey", "key": "ApCzSG8k7Tr4aM6e4OJRExN7cNtvH21L9azbh+uRrvt4" }, { "@type": "/cosmos.crypto.secp256k1.PubKey", "key": "Ah91erz8ChNanqLe9ea948rvAiXMCRlR5Ka7EE/c0xUK" }, { "@type": "/cosmos.crypto.secp256k1.PubKey", "key": "A0OjtIUCFJM3AobJ9HJTWKP9RZV2+WPcwVjLgsAidrZ/" } ] }, "mode_info": { "multi": { "bitarray": { "extra_bits_stored": 3, "elems": "wA==" }, "mode_infos": [ { "single": { "mode": "SIGN_MODE_LEGACY_AMINO_JSON" } }, { "single": { "mode": "SIGN_MODE_LEGACY_AMINO_JSON" } } ] } }, "sequence": "1" } ], "fee": { "amount": [ { "denom": "ahpx", "amount": "1000000" } ], "gas_limit": "200000", "payer": "", "granter": "" } }, "signatures": [ "CkCEeIbeGc+I1ipZuhp/0KhVNnWAv2tTlvgo5x61lzk1KHmLPV38m/YFurrFt5cm5+fqIXrn+FlOjrJuzBhw8ogYCkCawm9mpXsBHk0CFsE5618fVnvScEkfrzW0c2jCcjqV8EPuj3ut74UWzZyQkwtJGxUWtro9EgnGsB7Di1Gzizst" ] } ``` ### Step 5: Broadcast transaction ```sh theme={null} hyperpaxd tx broadcast signedTx.json \ --chain-id=hyperpax_125-4 \ --broadcast-mode=block ``` # Pending state Source: https://sidiorresearchlabs.mintlify.app/protocol/concepts/pending-state # Pending State When a transaction is submitted to the Ethereum network, it first goes into the pending status, waiting to be executed by the nodes. A transaction can be in the pending state for a longer duration if the gas price is set very low in the transaction and the nodes are busy processing other higher gas price transactions. During the pending state, the transaction initiator is allowed to change the transaction fields at any time. They can do so by sending another transaction with the same nonce. ## Prerequisite Readings * [Cosmos SDK Mempool](https://docs.cosmos.network/main/building-apps/app-mempool) ## HyperPaxeer vs Ethereum In Ethereum, pending blocks are generated as they are queued for production by miners. These pending blocks include pending transactions that are picked out by miners, based on the highest reward paid in gas. This mechanism exists as block finality is not possible on the Ethereum network. Blocks are committed with probabilistic finality, which means that transactions and blocks become less likely to become reverted as more time (and blocks) passes. HyperPaxeer is designed quite differently on this front as there is no concept of a "pending state". HyperPaxeer uses [Tendermint Core](https://docs.tendermint.com/) BFT consensus which provides instant finality for transaction. For this reason, HyperPaxeer EVM does not require a pending state mechanism, as all (if not most) of the transactions will be committed to the next block (avg. block time on Cosmos chains is \~8s). However, this causes a few hiccups in terms of the Ethereum Web3-compatible queries that can be made to pending state. Another significant difference with Ethereum, is that blocks are produced by validators or block producers, who include transactions from their local mempool into blocks in a first-in-first-out (FIFO) fashion. Transactions on HyperPaxeer cannot be ordered or cherry picked out from the Tendermint node [mempool](https://docs.tendermint.com/v0.34/tendermint-core/mempool.html). ## Pending State Queries HyperPaxeer will make queries which will account for any unconfirmed transactions present in a node's transaction mempool. A pending state query made will be subjective and the query will be made on the target node's mempool. Thus, the pending state will not be the same for the same query to two different nodes. ### JSON-RPC Calls on Pending Transactions * [`eth_getBalance`](./../../develop/api/ethereum-json-rpc/methods#eth_getbalance) * [`eth_getTransactionCount`](./../../develop/api/ethereum-json-rpc/methods#eth_gettransactioncount) * [`eth_getBlockTransactionCountByNumber`](./../../develop/api/ethereum-json-rpc/methods#eth_getblocktransactioncountbynumber) * [`eth_getBlockByNumber`](./../../develop/api/ethereum-json-rpc/methods#eth_getblockbynumber) * [`eth_getTransactionByHash`](./../../develop/api/ethereum-json-rpc/methods#eth_gettransactionbyhash) * [`eth_getTransactionByBlockNumberAndIndex`](./../../develop/api/ethereum-json-rpc/methods#eth_gettransactionbyblockhashandindex) * [`eth_sendTransaction`](./../../develop/api/ethereum-json-rpc/methods#eth_sendtransaction) # Signing Source: https://sidiorresearchlabs.mintlify.app/protocol/concepts/signing # Signing Signing is the process of creating a digital signature using a private key to verify a transaction on the HyperPaxeer network. The signature is created using a specific cryptographic algorithm that ensures the authenticity and integrity of the transaction using methods like [wallets](https://academy.evmosd.org/articles/wallet) and the [CLI](./../Paxeer-Network-cli). There are different methods for signing, but one of the most commonly used methods is the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard. HyperPaxeer leverages EIP-712 to homogenize the interaction between the EVM and Cosmos. ## EIP-712 EIP-712 introduces a standard for signing "typed-data" in a human-readable format. This standard allowed users to understand the data they are signing more easily and provides a more secure way to sign data, as it is less susceptible to phishing attacks. EIP-712 is not an Ethereum transaction type, but a method for signing structured data that can be used for authentication and indirect influence on program logic. To support signing Cosmos transactions, HyperPaxeer utilizes the EIP-712 protocol for encoding Cosmos transactions in a format that can be understood and processed by Ethereum signers, including Ledger hardware wallets. This approach helps to overcome the limitations of Ethereum signing devices, which often do not support signing arbitrary bytes for security reasons. The process works as follows: 1. A Cosmos transaction is represented as a JSON sign-doc. 2. The JSON sign-doc is converted to an EIP-712 object, which consists of types and messages. 3. The EIP-712 object is signed using an Ethereum signer, such as MetaMask or a Ledger hardware device. 4. The same process is performed on the node to verify the signature. By using EIP-712 for signing Cosmos transactions, HyperPaxeer ensures compatibility with popular Ethereum signing tools like MetaMask and Ledger devices as well as Keplr. This compatibility makes it easier for users to interact with both Ethereum and Cosmos networks, ultimately fostering greater interoperability between the two ecosystems. :::note HyperPaxeerJS supports signing with EIP-712. More information about the library can be found [here](https://github.com/Paxeer-Network/Paxeer-Networkjs). Supported: [Ledger support](https://academy.evmosd.org/articles/beginner/connect-your-wallet/ledger) and [CLI Commands](./../Paxeer-Network-cli/cli-commands). ::: # Tokens Source: https://sidiorresearchlabs.mintlify.app/protocol/concepts/tokens # Tokens ## Native token The native token secures HyperPaxeer, pays gas, supports governance flows, and denominates validator and protocol rewards. | Field | Value | | ----------------- | -------------------- | | Display symbol | `HPX` / `hpx` | | Base denomination | `ahpx` | | Decimals | `18` | | Conversion | `1 hpx = 10^18 ahpx` | HyperPaxeer uses an atto-denominated base unit to maintain parity with Ethereum-style 18-decimal tooling: ```text theme={null} 1 hpx = 1,000,000,000,000,000,000 ahpx 1 ETH = 1,000,000,000,000,000,000 wei ``` ## Asset types HyperPaxeer supports: * Native `hpx` / `ahpx` balances * Cosmos SDK coins, including IBC-transferred assets * EVM tokens, including ERC-20, ERC-721, and ERC-1155 contracts ## Cosmos coins Cosmos balances are used for staking, IBC transfers, governance deposits, and SDK-module operations. Native balances use the `ahpx` base denomination. ## EVM tokens HyperPaxeer is EVM-compatible and supports standard Solidity token contracts. Use the EVM chain ID `125` and 18-decimal native currency configuration when integrating wallets, viem, ethers.js, Foundry, Hardhat, or other Ethereum tooling. ## Related docs * [Current network facts](/current-network) * [Network configuration](/configuration) # Transactions Source: https://sidiorresearchlabs.mintlify.app/protocol/concepts/transactions # Transactions A transaction refers to an action initiated by an account which changes the state of the blockchain. To effectively perform the state change, every transaction is broadcasted to the whole network. Any node can broadcast a request for a transaction to be executed on the blockchain state machine; after this happens, a validator will validate, execute the transaction and propagate the resulting state change to the rest of the network. To process every transaction, computation resources on the network are consumed. Thus, the concept of "gas" arises as a reference to the computation required to process the transaction by a validator. Users have to pay a fee for this computation, all transactions require an associated fee. This fee is calculated based on the gas required to execute the transaction and the gas price. Additionally, a transaction needs to be signed using the sender's private key. This proves that the transaction could only have come from the sender and was not sent fraudulently. In a nutshell, the transaction lifecycle once a signed transaction is submitted to the network is the following: * A transaction hash is cryptographically generated. * The transaction is broadcasted to the network and added to a transaction pool consisting of all other pending network transactions. * A validator must pick your transaction and include it in a block in order to verify the transaction and consider it "successful". For a more detailed explanation of the transaction lifecyle, see [the corresponding section](https://docs.cosmos.network/main/basics/tx-lifecycle). The transaction hash is a unique identifier and can be used to check transaction information, for example, the events emitted, if was successful or not. Transactions can fail for various reasons. For example, the provided gas or fees may be insufficient. Also, the transaction validation may fail. Each transaction has specific conditions that must fullfil to be considered valid. A widespread validation is that the sender is the transaction signer. In such a case, if you send a transaction where the sender address is different than the signer's address, the transation will fail, even if the fees are sufficient. Nowadays, transactions can not only perform state transitions on the chain in which are submitted, but also can execute transactions on another blockchains. Interchain transactions are possible through the [Inter-Blockchain Communication protocol (IBC)](https://ibcprotocol.org/). Find a more detailed explanation on the section below. ## Transaction Types HyperPaxeer supports two transaction types: 1. Cosmos transactions 2. Ethereum transactions This is possible because HyperPaxeer uses the [Cosmos-SDK](https://docs.cosmos.network/main) and implements the [Ethereum Virtual Machine](https://ethereum.org/en/developers/docs/evm/) as a module. In this way, HyperPaxeer provides the features and functionalities of Ethereum and Cosmos chains combined, and more. Although most of the information included on both of these transaction types is similar, there are differences among them. An important difference, is that Cosmos transactions allow multiple messages on the same transaction. Conversely, Ethereum transactions don't have this possibility. To bring these two types together, HyperPaxeer implements Ethereum transactions as a single [`sdk.Msg`](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Msg) contained in an [`auth.StdTx`](https://pkg.go.dev/github.com/cosmos/cosmos-sdk/x/auth#StdTx). All relevant Ethereum transaction information is contained in this message. This includes the signature, gas, payload, etc. Find more information about these two types on the following sections. ### Cosmos Transactions On Cosmos chains, transactions are comprised of metadata held in contexts and `sdk.Msg`s that trigger state changes within a module through the module's Protobuf [Msg service](https://docs.cosmos.network/main/building-modules/msg-services). When users want to interact with an application and make state changes (e.g. sending coins), they create transactions. Cosmos transactions can have multiple `sdk.Msg`s. Each of these must be signed using the private key associated with the appropriate account(s), before the transaction is broadcasted to the network. A Cosmos transaction includes the following information: * `Msgs`: an array of msgs (`sdk.Msg`) * `GasLimit`: option chosen by the users for how to calculate how much gas they will need to pay * `FeeAmount`: max amount user is willing to pay in fees * `TimeoutHeight`: block height until which the transaction is valid * `Signatures`: array of signatures from all signers of the tx * `Memo`: a note or comment to send with the transaction To submit a Cosmos transaction, users must use one of the provided clients. ### Ethereum Transactions Ethereum transactions refer to actions initiated by EOAs (externally-owned accounts, managed by humans), rather than internal smart contract calls. Ethereum transactions transform the state of the EVM and therefore must be broadcasted to the entire network. Ethereum transactions also require a fee, known as `gas`. ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)) introduced the idea of a base fee, along with a priority fee which serves as an incentive for miners to include specific transactions in blocks. There are several categories of Ethereum transactions: * regular transactions: transactions from one account to another * contract deployment transactions: transactions without a `to` address, where the contract code is sent in the `data` field * execution of a contract: transactions that interact with a deployed smart contract, where the `to` address is the smart contract address An Ethereum transaction includes the following information: * `recipient`: receiving address * `signature`: sender's signature * `nonce`: counter of tx number from account * `value`: amount of ETH to transfer (in wei) * `data`: include arbitrary data. Used when deploying a smart contract or making a smart contract method call * `gasLimit`: max amount of gas to be consumed * `maxPriorityFeePerGas`: mas gas to be included as tip to validators * `maxFeePerGas`: max amount of gas to be paid for tx For more information on Ethereum transactions and the transaction lifecycle, [go here](https://ethereum.org/en/developers/docs/transactions/). HyperPaxeer supports the following Ethereum transactions. :::tip **Note**: Unprotected legacy transactions are not supported by default. ::: * Dynamic Fee Transactions ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)) * Access List Transactions ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930)) * Legacy Transactions ([EIP-2718](https://eips.ethereum.org/EIPS/eip-2718)) HyperPaxeer is capable of processing Ethereum transactions by wrapping them on a `sdk.Msg`. HyperPaxeer achieves this by using the `MsgEthereumTx`. This message encapsulates an Ethereum transaction as an SDK message and contains the necessary transaction data fields. One remark about the `MsgEthereumTx` is that it implements both the `sdk.Msg` and `sdk.Tx` interfaces (generally SDK messages only implement the former, while the latter is a group of messages bundled together). The reason of this, is because the `MsgEthereumTx` must not be included in a `auth.StdTx` (SDK's standard transaction type) as it performs gas and fee checks using the Ethereum logic from Geth instead of the Cosmos SDK checks done on the auth module `AnteHandler`. #### Ethereum Tx Type There are three types of transaction types used in HyperPaxeer's [Go Ethereum](https://github.com/ethereum/go-ethereum/blob/b946b7a13b749c99979e312c83dce34cac8dd7b1/core/types/transaction.go#L43-L48) implementation that came from Ethereum Improvement Proposals(EIPs): 1. LegacyTxType (EIP-155): The LegacyTxType represents the original transaction format that existed before Ethereum Improvement Proposal (EIP) 155. These transactions do not include a chain ID, which makes them vulnerable to replay attacks. EIP-155 was introduced to solve this problem by incorporating a chain ID, which uniquely identifies a specific Ethereum chain to prevent cross-chain replay attacks. 2. AccessListTxType (EIP-2930): AccessListTxType was introduced with EIP-2930 as part of the Berlin upgrade. This new transaction type allows users to specify an access list – a list of addresses and storage keys that the transaction plans to access. The primary goal of access lists is to mitigate some of the gas cost increases introduced with EIP-2929, which increased gas costs for state access operations to improve denial-of-service (DoS) attack resistance. By specifying an access list, users can avoid paying higher gas costs for subsequent accesses to the same addresses and storage keys within the same transaction. 3. DynamicFeeTxType (EIP-1559): DynamicFeeTxType was introduced with EIP-1559 as part of the London upgrade. This transaction type brought significant changes to Ethereum's fee market, with the aim of making gas fees more predictable and improving user experience. EIP-1559 transactions include two main components: a base fee and a priority fee (or tip). The base fee is algorithmically determined by the network, while the priority fee is set by users to incentivize miners to include their transaction. The base fee is burned, effectively reducing the overall ETH supply, while the priority fee goes to miners as a reward for their work. DynamicFeeTxType transactions allow for more predictable and efficient gas fee management. These transaction types represent Ethereum's continuous evolution and improvements to its network, helping address challenges related to scalability, security, and user experience. ### Interchain Transactions Interchain transactions refer to the transfer of digital assets or data between two or more different blockchain networks. Each blockchain network has its own unique protocol and data structure, making it difficult to directly transfer assets or data from one blockchain to another. Interchain transactions allow for the transfer of assets and data between different blockchains by using intermediary mechanisms or protocols. One such mechanism is a cross-chain bridge, which acts as a connector between different blockchains, enabling the transfer of assets or data. Cross-chain bridges typically require some form of trust or consensus mechanism to ensure the security and integrity of the transaction. Another possibility is to use the [IBC (Inter-Blockchain Communication)](https://ibcprotocol.org/) protocol. To make an interchain transaction using IBC a user needs to: * Choose the source and destination blockchain networks that the user wants to transfer assets or data between. * Ensure that both blockchain networks have implemented the IBC protocol * Ensure there's a connection and channel established between the two blockchain networks using IBC * Initiate the transfer of assets or data: this is done by sending a transaction from the source blockchain to the destination blockchain through the IBC channel Interchain transactions are becoming increasingly important as the number of different blockchain networks and applications continues to grow. They enable the interoperability of different blockchain networks, allowing for greater flexibility and efficiency in the transfer of digital assets and data. ## Transaction Receipts A transaction receipt shows data returned by an Ethereum client to represent the result of a particular transaction, including a hash of the transaction, its block number, the amount of gas used, and, in case of deployment of a smart contract, the address of the contract. Additionally, it includes custom information from the events emitted in the smart contract. A receipt contains the following information: * `transactionHash` : hash of the transaction. * `transactionIndex`: integer of the transactions index position in the block. * `blockHash`: hash of the block where this transaction was in. * `blockNumber`: block number where this transaction was in. * `from`: address of the sender. * `to`: address of the receiver. null when its a contract creation transaction. * `cumulativeGasUsed` : The total amount of gas used when this transaction was executed in the block. * `effectiveGasPrice` : The sum of the base fee and tip paid per unit of gas. * `gasUsed` : The amount of gas used by this specific transaction alone. * `contractAddress` : The contract address created, if the transaction was a contract creation, otherwise null. * `logs`: Array of log objects, which this transaction generated. * `logsBloom`: Bloom filter for light clients to quickly retrieve related logs. * `type`: integer of the transaction type, 0x00 for legacy transactions, 0x01 for access list types, 0x02 for dynamic fees. It also returns either. * `root` : transaction stateroot (pre Byzantium) * `status`: either 1 (success) or 0 (failure) # Faq Source: https://sidiorresearchlabs.mintlify.app/protocol/faq # Frequently Asked Questions ## Concepts
What is the difference between "secp256k1" and "ed25519"? secp256k1 and ed25519 are both popular cryptographic algorithms used for digital signatures and key generation, but they have some differences in terms of security, performance, and compatibility with different systems. secp256k1 is an elliptic curve algorithm that is widely used in Bitcoin and many other cryptocurrencies. It provides 128-bit security, which is considered sufficient for most practical purposes. secp256k1 is relatively fast and efficient, making it a good choice for applications that require high performance. It is widely supported by most cryptographic libraries and software, which makes it a good choice for cross-platform applications. ed25519 is a newer elliptic curve algorithm that provides 128-bit security, similar to secp256k1. However, ed25519 is generally considered to be more secure than secp256k1, due to its resistance to certain types of attacks such as [side-channel attacks](https://en.wikipedia.org/wiki/Side-channel_attack). It is also faster than many other elliptic curve algorithms, including secp256k1, making it a good choice for applications that require high performance. In terms of compatibility, secp256k1 is more widely supported by existing systems, while ed25519 is less widely supported. However, ed25519 is gaining popularity, and is supported by many cryptographic libraries and software. When choosing between secp256k1 and ed25519, you should consider your specific needs in terms of security, performance, and compatibility. If you are building an application that requires high performance and compatibility with existing systems, secp256k1 may be a better choice. However, if you are building an application that requires a higher level of security and performance, and you can afford to sacrifice some compatibility, ed25519 may be a better choice.
Where can I find the Protobuf interfaces for HyperPaxeer? Head over to our [Buf](https://buf.build/Paxeer-Network).
# Ibc channels Source: https://sidiorresearchlabs.mintlify.app/protocol/ibc-channels # IBC Channels IBC channels are a key component of the Inter-blockchain Communication (IBC) protocol used in the Cosmos ecosystem. IBC channels enable communication between different Cosmos chains, allowing the transfer of tokens and data between them. Each IBC channel has a unique identifier known as the channel ID, which is used to specify the source and destination of a transfer. The channel ID can change depending on which relayers are active, so it's important to double-check the channel IDs before making a transfer. :::tip You can also view a full list of IBC Relayers and Channels on [Mintscan](https://www.mintscan.io/Paxeer-Network/relayers) ::: # Protocol Source: https://sidiorresearchlabs.mintlify.app/protocol/index Technical architecture and core network design. # Technical Architecture HyperPaxeer is a capital orchestration network built as part of the Alexandria Fork upgrade, migrating validators from the original HyperPaxeer (geth PoS, chain ID 229) to this new high-throughput Proof-of-Stake EVM blockchain (chain ID 125). It is built using the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk/) which runs on top of the [CometBFT](https://github.com/cometbft/cometbft) consensus engine, providing full Ethereum compatibility and interoperability with instant deterministic finality and sub-second block production. ## Network Information | Parameter | Value | | -------------------- | ----------------------------------- | | Chain ID (Cosmos) | `hyperpax_125-1` | | EVM Chain ID | `125` | | Token Symbol | `HPX` / `hpx` | | Base Denomination | `ahpx` | | Display Denomination | `hpx` | | Decimals | `18` | | Bech32 Prefix | `pax` | | RPC Endpoint | `https://public-rpc.paxeer.app/rpc` | | Block Explorer | [paxscan.io](https://paxscan.io) | This architecture allows users to perform both Cosmos and EVM formatted transactions, developers to scale EVM dApps cross-chain via [IBC](https://cosmos.network/ibc), and tokens and assets in the network to come from different independent sources. HyperPaxeer enables these key features by: * Leveraging [modules](https://docs.cosmos.network/v0.47/build/building-modules/intro) and other mechanisms implemented by the [Cosmos SDK](https://docs.cosmos.network/). * Implementing CometBFT's Application Blockchain Interface ([ABCI](https://docs.tendermint.com/master/spec/abci/)) to manage the blockchain. * Utilizing [`geth`](https://github.com/ethereum/go-ethereum) as a library to promote code reuse and improve maintainability. * Exposing a fully compatible Web3 [JSON-RPC](./../develop/api/ethereum-json-rpc/methods) layer for interacting with existing Ethereum clients and tooling (Metamask, Remix, Truffle, etc). The sum of these features allows developers to leverage existing Ethereum ecosystem tooling and software to seamlessly deploy smart contracts which interact with the rest of the Cosmos [ecosystem](https://cosmos.network/ecosystem). ## Cosmos SDK HyperPaxeer enables the full composability and modularity of the [Cosmos SDK](https://docs.cosmos.network/). As a Cosmos chain, HyperPaxeer is a sovereign blockchain with its own native token, that can connect to other chains through IBC. It includes standard modules from the Cosmos SDK, that work side to side with HyperPaxeer-specific modules, built by the HyperPaxeer core development team. Check out the [list of modules](modules/index.md) to get an overview of what each module is responsible for. ## CometBFT & ABCI [CometBFT](https://github.com/cometbft/cometbft) consists of two chief technical components: a blockchain consensus engine and a generic application interface. The consensus engine ensures that the same transactions are recorded on every machine in the same order. The application interface, called the [Application Blockchain Interface (ABCI)](https://docs.tendermint.com/master/spec/abci/), enables the transactions to be processed in any programming language. CometBFT has evolved to be a general-purpose blockchain consensus engine that can host arbitrary application states. Since it can replicate arbitrary applications, it can be used as a plug-and-play replacement for the consensus engines of other blockchains. HyperPaxeer is an example of an ABCI application replacing Ethereum's PoW via CometBFT's consensus engine. Another example of a cryptocurrency application built on CometBFT is the Cosmos network. CometBFT can decompose the blockchain design by offering a very simple API (ie. the ABCI) between the application process and consensus process. ## EVM Compatibility HyperPaxeer enables EVM compatibility by implementing various components that together support all the EVM state transitions while ensuring the same developer experience as Ethereum: * Ethereum's transaction format as a Cosmos SDK `Tx` and `Msg` interface * Ethereum's `secp256k1` curve for the Cosmos Keyring * `StateDB` interface for state updates and queries * [JSON-RPC](../develop/api/ethereum-json-rpc) client for interacting with the EVM Most components are implemented in the [EVM module](modules/evm.md) To achieve a seamless developer UX, however, some of the components are implemented outside of the module. If you want to learn more about how HyperPaxeer achieves EVM compatibility as a Cosmos chain, we recommend understanding the following concepts: * [Accounts](./concepts/accounts.md) * [Gas and Fees](./concepts/gas-and-fees.md) * [Token representations](./concepts/tokens.md) * [Transactions](./concepts/transactions.md) ## Contributing There are several ways to contribute to the HyperPaxeer core protocol. To get some hands-on experience, we recommend you spin up a local node using the [Paxeer CLI](./paxeer-cli) and interact with it through queries and transactions using the supported [clients](../develop/api#clients). Then if you're hooked you can * Contribute open-source to [issues on GitHub](https://github.com/paxeer-network/PaxeerNetwork-Alexandria-Fork/issues) using the [Contributor Guidelines](https://github.com/paxeer-network/PaxeerNetwork-Alexandria-Fork/blob/main/CONTRIBUTING.md) * Search for [bugs and earn a bounty](bugs.md) # Metrics Source: https://sidiorresearchlabs.mintlify.app/protocol/metrics # Metrics HyperPaxeer nodes can enable [Cosmos SDK telemetry](https://docs.cosmos.network/main/learn/advanced/telemetry) to allow for observing and gathering insights about the HyperPaxeer application. Under the hood, it uses the [`go-metrics`](https://github.com/hashicorp/go-metrics) package and the Prometheus client library to expose different [types of metrics](https://prometheus.io/docs/concepts/metric_types/) like gauges and counters. For best practices on how to use different metrics types, check this [blog article](https://blog.pvincent.io/2017/12/prometheus-blog-series-part-2-metric-types/). Find below a list of supported HyperPaxeer modules with custom metrics and telemetry. Using the metrics you can e.g. run performance profiles and display them in a [Grafana](https://grafana.com/) dashboard. ## Supported Metrics | Metric | Description | Unit | Type | | :--------------------------------------------- | :----------------------------------------------------------------------------------------------------------- | :------- | :-------- | | `feemarket_base_fee` | Amount of base fee per EIP-1559 block | token | gauge | | `feemarket_block_gas` | Amount of gas used in an EIP-1559 block | token | gauge | | `erc20_ibc_on_recv_total` | Total amount of times an IBC coin was autoconverted to an ERC20 token in the ibc `onRecvPacket` callback | transfer | counter | | `erc20_ibc_err_total` | Total amount of times an IBC coin autoconvertion to ERC20 token failed during an ibc transaction | transfer | counter | | `erc20_ibc_transfer_total` | Total amount of times an IBC coin or its ERC20 representation was transferred via ibc (outgoing transaction) | transfer | counter | | `tx_msg_convert_coin_amount_total` | Total amount of converted coins using a `ConvertCoin` msg | token | counter | | `tx_msg_convert_coin_total` | Total number of txs with a `ConvertCoin` msg | tx | counter | | `tx_msg_convert_erc20_amount_total` | Total amount of converted erc20 using a `ConvertERC20` msg | token | counter | | `tx_msg_convert_erc20_total` | Total number of txs with a `ConvertERC20` msg | tx | counter | | `tx_msg_ethereum_tx_total` | Total number of txs processed via the EVM | tx | counter | | `tx_msg_ethereum_tx_gas_used_total` | Total amount of gas used by an ethereum tx | gas | counter | | `tx_msg_ethereum_tx_gas_limit_per_gas_used` | Ratio of gas limit to gas used for an ethereum tx | ratio | gauge | | `tx_msg_ethereum_tx_incentives_total` | Total number of txs with an incentivized contract processed via the EVM | tx | counter | | `tx_msg_ethereum_tx_incentives_gas_used_total` | Total amount of gas used by txs with an incentivized contract processed via the EVM | gas | counter | | `inflation_allocate_total` | Total amount of tokens allocated through inflation | token | counter | | `inflation_allocate_staking_total` | Total amount of tokens allocated through inflation to staking | token | counter | | `inflation_allocate_incentives_total` | Total amount of tokens allocated through inflation to incentives | token | counter | | `inflation_allocate_community_pool_total` | Total amount of tokens allocated through inflation to community pool | token | counter | | `tx_create_clawback_vesting_account_gas_used` | Total amount of gas used by a `CreateClawbackVestingAccount` msg | gas | counter | | `tx_fund_vesting_account_gas_used` | Total amount of gas used by a `FundVestingAccount` msg | gas | counter | | `tx_clawback_gas_used` | Total amount of gas used by a `Clawback` msg | gas | counter | | `tx_update_vesting_funder_gas_used` | Total amount of gas used by a `UpdateVestingFunder` msg | gas | counter | | `epochs_begin_blocker` | Time spent during `BeginBlocker` of the `x/epochs` module | ms | histogram | | `burned_tx_fee_amount` | Total amount of fees burned on a tx | token | counter | # Module accounts Source: https://sidiorresearchlabs.mintlify.app/protocol/module-accounts # Module Accounts Some modules have their own module account. Think of this as a wallet that can only be controlled by that module. Below is a table of modules, their respective wallet addresses and permissions: ## List of Module Accounts | Name | Address | Permissions | | :----------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------- | | `erc20` | [HyperPaxeer1glht96kr2rseywuvhhay894qw7ekuc4qg9z5nw](https://www.mintscan.io/Paxeer-Network/account/Paxeer-Network1glht96kr2rseywuvhhay894qw7ekuc4qg9z5nw) | `minter` `burner` | | `fee_collector` | [HyperPaxeer17xpfvakm2amg962yls6f84z3kell8c5ljcjw34](https://www.mintscan.io/Paxeer-Network/account/Paxeer-Network17xpfvakm2amg962yls6f84z3kell8c5ljcjw34) | `none` | | `inflation` | [HyperPaxeer1d4e35hk3gk4k6t5gh02dcm923z8ck86qygxf38](https://www.mintscan.io/Paxeer-Network/account/Paxeer-Network1d4e35hk3gk4k6t5gh02dcm923z8ck86qygxf38) | `minter` | | `transfer` | [HyperPaxeer1yl6hdjhmkf37639730gffanpzndzdpmhv788dt](https://www.mintscan.io/Paxeer-Network/account/Paxeer-Network1yl6hdjhmkf37639730gffanpzndzdpmhv788dt) | `minter` `burner` | | `bonded_tokens_pool` | [HyperPaxeer1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3h6cprl](https://www.mintscan.io/Paxeer-Network/account/Paxeer-Network1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3h6cprl) | `burner` `staking` | | `not_bonded_tokens_pool` | [HyperPaxeer1tygms3xhhs3yv487phx3dw4a95jn7t7lr6ys4t](https://www.mintscan.io/Paxeer-Network/account/Paxeer-Network1tygms3xhhs3yv487phx3dw4a95jn7t7lr6ys4t) | `burner` `staking` | | `gov` | [HyperPaxeer10d07y265gmmuvt4z0w9aw880jnsr700jcrztvm](https://www.mintscan.io/Paxeer-Network/account/Paxeer-Network10d07y265gmmuvt4z0w9aw880jnsr700jcrztvm) | `burner` | | `distribution` | [HyperPaxeer1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8974jnh](https://www.mintscan.io/Paxeer-Network/account/Paxeer-Network1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8974jnh) | `none` | | `evm` | [HyperPaxeer1vqu8rska6swzdmnhf90zuv0xmelej4lq0n56wq](https://www.mintscan.io/Paxeer-Network/account/Paxeer-Network1vqu8rska6swzdmnhf90zuv0xmelej4lq0n56wq) | `minter` `burner` | | `ibc` | [HyperPaxeer1a53udazy8ayufvy0s434pfwjcedzqv345dnt3x](https://www.mintscan.io/Paxeer-Network/account/Paxeer-Network1a53udazy8ayufvy0s434pfwjcedzqv345dnt3x) | `minter` `burner` | ## Account Permissions * The `burner` permission means this account has the permission to burn or destroy tokens. * The `minter` permission means this account has permission to mint or create new tokens. * The `staking` permission means this account has permission to stake tokens on behalf of its owner. ## IBC Module Accounts Additionally, there are module accounts associated with IBC transfers. For each IBC connection, there's an account of type `ModuleAccount` used to escrow the transferred coins when HyperPaxeer is the source chain. Their addresses are derived using the first 20 bytes of the SHA256 checksum of the account name and following the format as outlined in [ADR 028](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-028-public-key-addresses.md): ```go theme={null} // accountName is composed by the current version the IBC transfer module supports (in this case, ics20-1), the portID (transfer) and the channelID accountName := Version + "\0" + portID + "/" + channelID addr := sha256.Sum256(accountName)[:20] // example for channel-0 addr := sha256.Sum256("ics20-1\0transfer/channel-0")[:20] ``` This can be calculated with the [`GetEscrowAccount` function on IBC-go](https://github.com/cosmos/ibc-go/blob/c56f78905a5d2db01d867381d106c403fa9e5c4b/modules/apps/transfer/types/keys.go#L41-L55). :::tip **Note**: These escrow accounts are not listed when performing the query: ```shell theme={null} hyperpaxd q auth module-accounts ``` This happens because the [`GetModuleAccount` function](https://github.com/cosmos/cosmos-sdk/blob/74d7a0dfcd9f47d8a507205f82c264a269ef0612/x/auth/keeper/keeper.go#L194-L224) used on the query considers only the accounts on the [`permAddrs` map of the `AccountKeeper`](https://github.com/cosmos/cosmos-sdk/blob/74d7a0dfcd9f47d8a507205f82c264a269ef0612/x/auth/keeper/keeper.go#L54-L68). This address map is set at compile time and cannot be changed on runtime. ::: # Epochs Source: https://sidiorresearchlabs.mintlify.app/protocol/modules/epochs # `epochs` ## Abstract This document specifies the internal `x/epochs` module of the HyperPaxeer Hub. Often, when working with the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk), we would like to run certain pieces of code every so often. The purpose of the `epochs` module is to allow other modules to maintain that they would like to be signaled once in a time period. So, another module can specify it wants to execute certain code once a week, starting at UTC-time = x. `epochs` creates a generalized epoch interface to other modules so they can be more easily signaled upon such events. ## Contents 1. **[Concept](#concepts)** 2. **[State](#state)** 3. **[Events](#events)** 4. **[Keeper](#keepers)** 5. **[Hooks](#hooks)** 6. **[Queries](#queries)** 7. **[Future improvements](#future-improvements)** ## Concepts The `epochs` module defines on-chain timers that execute at fixed time intervals. Other HyperPaxeer modules can then register logic to be executed at the timer ticks. We refer to the period in between two timer ticks as an "epoch". Every timer has a unique identifier, and every epoch will have a start time and an end time, where `end time = start time + timer interval`. ## State ### State Objects The `x/epochs` module keeps the following `objects in state`: | State Object | Description | Key | Value | Store | | ------------ | ------------------- | -------------------- | ------------------- | ----- | | `EpochInfo` | Epoch info bytecode | `[]byte{identifier}` | `[]byte{epochInfo}` | KV | #### EpochInfo An `EpochInfo` defines several variables: 1. `identifier` keeps an epoch identification string 2. `start_time` keeps the start time for epoch counting: if block height passes `start_time`, then `epoch_counting_started` is set 3. `duration` keeps the target epoch duration 4. `current_epoch` keeps the current active epoch number 5. `current_epoch_start_time` keeps the start time of the current epoch 6. `epoch_counting_started` is a flag set with `start_time`, at which point `epoch_number` will be counted 7. `current_epoch_start_height` keeps the start block height of the current epoch ```protobuf theme={null} message EpochInfo { string identifier = 1; google.protobuf.Timestamp start_time = 2 [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"start_time\"" ]; google.protobuf.Duration duration = 3 [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.jsontag) = "duration,omitempty", (gogoproto.moretags) = "yaml:\"duration\"" ]; int64 current_epoch = 4; google.protobuf.Timestamp current_epoch_start_time = 5 [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"current_epoch_start_time\"" ]; bool epoch_counting_started = 6; reserved 7; int64 current_epoch_start_height = 8; } ``` The `epochs` module keeps these `EpochInfo` objects in state, which are initialized at genesis and are modified on begin blockers or end blockers. #### Genesis State The `x/epochs` module's `GenesisState` defines the state necessary for initializing the chain from a previously exported height. It contains a slice containing all the `EpochInfo` objects kept in state: ```go theme={null} // Genesis State defines the epoch module's genesis state type GenesisState struct { // list of EpochInfo structs corresponding to all epochs Epochs []EpochInfo `protobuf:"bytes,1,rep,name=epochs,proto3" json:"epochs"` } ``` ## Events The `x/epochs` module emits the following events: ### BeginBlocker | Type | Attribute Key | Attribute Value | | ------------- | ---------------- | ---------------- | | `epoch_start` | `"epoch_number"` | `{epoch_number}` | | `epoch_start` | `"start_time"` | `{start_time}` | ### EndBlocker | Type | Attribute Key | Attribute Value | | ----------- | ---------------- | ---------------- | | `epoch_end` | `"epoch_number"` | `{epoch_number}` | ## Keepers The `x/epochs` module only exposes one keeper, the epochs keeper, which can be used to manage epochs. ### Epochs Keeper Presently only one fully-permissioned epochs keeper is exposed, which has the ability to both read and write the `EpochInfo` for all epochs, and to iterate over all stored epochs. ```go theme={null} // Keeper of epoch nodule maintains collections of epochs and hooks. type Keeper struct { cdc codec.Codec storeKey storetypes.StoreKey hooks types.EpochHooks } ``` ```go theme={null} // Keeper is the interface for epoch module keeper type Keeper interface { // GetEpochInfo returns epoch info by identifier GetEpochInfo(ctx sdk.Context, identifier string) types.EpochInfo // SetEpochInfo set epoch info SetEpochInfo(ctx sdk.Context, epoch types.EpochInfo) // DeleteEpochInfo delete epoch info DeleteEpochInfo(ctx sdk.Context, identifier string) // IterateEpochInfo iterate through epochs IterateEpochInfo(ctx sdk.Context, fn func(index int64, epochInfo types.EpochInfo) (stop bool)) // Get all epoch infos AllEpochInfos(ctx sdk.Context) []types.EpochInfo } ``` ## Hooks The `x/epochs` module implements hooks so that other modules can use epochs to allow facets of the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) to run on specific schedules. ### Hooks Implementation ```go theme={null} // combine multiple epoch hooks, all hook functions are run in array sequence type MultiEpochHooks []types.EpochHooks // AfterEpochEnd is called when epoch is going to be ended, epochNumber is the // number of epoch that is ending func (mh MultiEpochHooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64) {...} // BeforeEpochStart is called when epoch is going to be started, epochNumber is // the number of epoch that is starting func (mh MultiEpochHooks) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64) {...} // AfterEpochEnd executes the indicated hook after epochs ends func (k Keeper) AfterEpochEnd(ctx sdk.Context, identifier string, epochNumber int64) {...} // BeforeEpochStart executes the indicated hook before the epochs func (k Keeper) BeforeEpochStart(ctx sdk.Context, identifier string, epochNumber int64) {...} ``` ### Recieving Hooks When other modules (outside of `x/epochs`) recieve hooks, they need to filter the value `epochIdentifier`, and only do executions for a specific `epochIdentifier`. The filtered values from `epochIdentifier` could be stored in the `Params` of other modules, so they can be modified by governance. Governance can change epoch periods from `week` to `day` as needed. ## Queries The `x/epochs` module provides the following queries to check the module's state. ```protobuf theme={null} service Query { // EpochInfos provide running epochInfos rpc EpochInfos(QueryEpochsInfoRequest) returns (QueryEpochsInfoResponse) {} // CurrentEpoch provide current epoch of specified identifier rpc CurrentEpoch(QueryCurrentEpochRequest) returns (QueryCurrentEpochResponse) {} } ``` ## Future Improvements ### Correct Usage In the current design, each epoch should be at least two blocks, as the start block should be different from the endblock. Because of this, the time allocated to each epoch will be `max(block_time x 2, epoch_duration)`. For example: if the `epoch_duration` is set to `1s`, and `block_time` is `5s`, actual epoch time should be `10s`. It is recommended to configure `epoch_duration` to be more than two times the `block_time`, to use this module correctly. If there is a mismatch between the `epoch_duration` and the actual epoch time, as in the example above, then module logic could become invalid. ### Block-Time Drifts This implementation of the `x/epochs` module has block-time drifts based on the value of `block_time`. For example: if we have an epoch of 100 units that ends at `t=100`, and we have a block at `t=97` and a block at `t=104` and `t=110`, this epoch ends at `t=104`, and the new epoch will start at `t=110`. There are time drifts here, varying about 1-2 blocks time, which will slow down epochs. # Erc20 Source: https://sidiorresearchlabs.mintlify.app/protocol/modules/erc20 # `erc20` :::tip **Note:** Working on a governance proposal related to the ERC-20 Module? Make sure to look at [HyperPaxeer Governance](https://academy.evmosd.org/articles/governance/), and specifically the [best practices](https://academy.evmosd.org/articles/governance/best-practices). ::: ## Abstract This document specifies the internal `x/erc20` module of the HyperPaxeer Hub. The `x/erc20` module enables the HyperPaxeer Hub to support a trustless, on-chain bidirectional internal conversion of tokens between HyperPaxeer' EVM and Cosmos runtimes, specifically the `x/evm` and `x/bank` modules. This allows token holders on HyperPaxeer to instantaneously convert their native Cosmos `sdk.Coins` (in this document referred to as "Coin(s)") to ERC-20 (aka "Token(s)") and vice versa, while retaining fungibility with the original asset on the issuing environment/runtime (EVM or Cosmos) and preserving ownership of the ERC-20 contract. This conversion functionality is fully governed by native HyperPaxeer token holders who manage the canonical `TokenPair` registrations (ie, ERC20 ←→ Coin mappings). This governance functionality is implemented using the Cosmos-SDKΒ `gov`Β module with custom proposal types for registering and updating the canonical mappings respectively. Why is this important? Cosmos and the EVM are two runtimes that are not compatible by default. The native Cosmos Coins cannot be used in applications that require the ERC-20 standard. Cosmos coins are held on the `x/bank` module (with access to module methods like querying the supply or balances) and ERC-20 Tokens live on smart contracts. This problem is similar to [wETH](https://coinmarketcap.com/alexandria/article/what-is-wrapped-ethereum-weth), with the difference, that it not only applies to gas tokens (like HyperPaxeer), but to all Cosmos Coins (IBC vouchers, staking and gov coins, etc.) as well. With the `x/erc20` users on HyperPaxeer can * use existing native cosmos assets (like OSMO or ATOM) on EVM-based chains, e.g. for Trading IBC tokens on DeFi protocols, buying NFT, etc. * transfer existing tokens on Ethereum and other EVM-based chains to HyperPaxeer to take advantage of application-specific chains in the Cosmos ecosystem * build new applications that are based on ERC-20 smart contracts and have access to the Cosmos ecosystem. ## Contents 1. **[Concepts](#concepts)** 2. **[State](#state)** 3. **[State Transitions](#state-transitions)** 4. **[Transactions](#transactions)** 5. **[Hooks](#hooks)** 6. **[Events](#events)** 7. **[Parameters](#parameters)** 8. **[Clients](#clients)** ## Concepts ### Token Pair The `x/erc20` module maintains a canonical one-to-one mapping of native Cosmos Coin denomination to ERC20 Token contract addresses (i.e `sdk.Coin` ←→ ERC20), called `TokenPair`. The conversion of the ERC20 tokens ←→ Coin of a given pair can be enabled or disabled via governance. ### Token Pair Registration Users can register a new token pair proposal through the governance module and initiate a vote to include the token pair in the module. Depending on which exists first, the coin or the token, you can either register a Cosmos Coin or a ERC20 Token to create a token pair. One proposal can inculde several token pairs. When the proposal passes, the erc20 module registers the Cosmos Coin and ERC20 Token mapping on the application's store. #### Registration of a Cosmos Coin A native Cosmos Coin corresponds to an `sdk.Coin` that is native to the bank module. It can be either the native staking/gas denomination (e.g. HyperPaxeer, ATOM, etc) or an IBC fungible token voucher (i.e. with denom format of `ibc/{hash}`). When a proposal is initiated for an existing native Cosmos Coin, the erc20 module will deploy a factory ERC20 contract, representing the ERC20 token for the token pair, giving the module ownership of that contract. #### Registration of an ERC20 token A proposal for an existing (i.e already deployed) ERC20 contract can be initiated too. In this case, the ERC20 maintains the original owner of the contract and uses an escrow & mint / burn & unescrow mechanism similar to the one defined by the [ICS20 - Fungible Token Transfer](https://github.com/cosmos/ibc/blob/master/spec/app/ics-020-fungible-token-transfer) specification. The token pair is composed of the original ERC20 token and a corresponding native Cosmos coin denomination. #### Token details and metadata Coin metadata is derived from the ERC20 token details (name, symbol, decimals) and vice versa. A special case is also described below that for the ERC20 representation of IBC fungible token (ICS20) vouchers. #### Coin Metadata to ERC20 details During the registration of a Cosmos Coin the following bank `Metadata` is used to deploy a ERC20 contract: * **Name** * **Symbol** * **Decimals** The native Cosmos Coin contains a more extensive metadata than the ERC20 and includes all necessary details for the conversion into a ERC20 Token, which requires no additional population of data. #### IBC voucher Metadata to ERC20 details IBC vouchers should comply to the following standard: * **Name**: `{NAME} channel-{channel}` * **Symbol**: `ibc{NAME}-{channel}` * **Decimals**: derived from bank `Metadata` #### ERC20 details to Coin Metadata During the Registration of an ERC20 Token the Coin metadata is derived from the ERC20 metadata and the bank metadata: * **Description**: `Cosmos coin token representation of {contractAddress}` * **DenomUnits**: * Coin: `0` * ERC20: `{uint32(erc20Data.Decimals)}` * **Base**: `{"erc20/%s", address}` * **Display**: `{erc20Data.Name}` * **Name**: `{types.CreateDenom(strContract)}` * **Symbol:** `{erc20Data.Symbol}` ### Token Pair Modifiers A valid token pair can be modified through several governance proposals. The internal conversion of a token pair can be toggled with `ToggleTokenConversionProposal`, so that the conversions between the token pair's tokens can be enabled or disabled. ### Token Conversion Once a token pair proposal passes, the module allows for the conversion of that token pair. Holders of native Cosmos coins and IBC vouchers on the HyperPaxeer chain can convert their Coin into ERC20 Tokens, which can then be used in HyperPaxeer EVM, by creating a `ConvertCoin` Tx. Vice versa, the `ConvertERC20` Tx allows holders of ERC20 tokens on the HyperPaxeer chain to convert ERC-20 tokens back to their native Cosmos Coin representation. Depending on the ownership of the ERC20 contract, the ERC20 tokens either follow a burn/mint or a transfer/escrow mechanism during conversion. ### Malicious Contracts The ERC20 standard is an interface that defines a set of method signatures (name, arguments and output) without defining its methods' internal logic. Therefore it is possible for developers to deploy contracts that contain hidden malicious behaviour within those methods. For instance, the ERC20 `transfer` method, which is responsible for sending an `amount` of tokens to a given `recipient` could include code to siphon some amount of tokens intended for the recipient into a different predefined account, which is owned by the malicious contract deployer. More sophisticated malicious implementations might also inherit code from customized ERC20 contracts that include malicous behaviour. For an overview of more extensive examples, please review the x/erc20 audit, section `IF-HyperPaxeer-06: IERC20 Contracts may execute arbitrary code`. As the `x/erc20` module allows any arbitrary ERC20 contract to be registered through governance, it is essential that the proposer or the voters manually verify during voting phase that the proposed contract uses the default ERC20.sol implementation. Here are our recommendations for the reviewing process: * contract solidity code should be verified and accessable (e.g. using an explorer) * contract should be audited by a reputabele auditor * inherited contracts need to be verified for correctness ## State ### State Objects The `x/erc20` module keeps the following objects in state: | State Object | Description | Key | Value | Store | | ------------------ | ---------------------------------------------- | --------------------------- | ------------------- | ----- | | `TokenPair` | Token Pair bytecode | `[]byte{1} + []byte(id)` | `[]byte{tokenPair}` | KV | | `TokenPairByERC20` | Token Pair id bytecode by erc20 contract bytes | `[]byte{2} + []byte(erc20)` | `[]byte(id)` | KV | | `TokenPairByDenom` | Token Pair id bytecode by denom string | `[]byte{3} + []byte(denom)` | `[]byte(id)` | KV | #### Token Pair One-to-one mapping of native Cosmos coin denomination to ERC20 token contract addresses (i.e `sdk.Coin` ←→ ERC20). ```go theme={null} type TokenPair struct { // address of ERC20 contract token Erc20Address string `protobuf:"bytes,1,opt,name=erc20_address,json=erc20Address,proto3" json:"erc20_address,omitempty"` // cosmos base denomination to be mapped to Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"` // shows token mapping enable status Enabled bool `protobuf:"varint,3,opt,name=enabled,proto3" json:"enabled,omitempty"` // ERC20 owner address ENUM (0 invalid, 1 ModuleAccount, 2 external address ContractOwner Owner `protobuf:"varint,4,opt,name=contract_owner,json=contractOwner,proto3,enum=HyperPaxeer.erc20.v1.Owner" json:"contract_owner,omitempty"` } ``` #### Token pair ID The unique identifier of a `TokenPair` is obtained by obtaining the SHA256 hash of the ERC20 hex contract address and the Coin denomination using the following function: ```tsx theme={null} tokenPairId = sha256(erc20 + "|" + denom) ``` #### Token Origin The `ConvertCoin` and `ConvertERC20` functionalities use the owner field to check whether the token being used is a native Coin or a native ERC20. The field is based on the token registration proposal type (`RegisterCoinProposal` = 1, `RegisterERC20Proposal` = 2). The `Owner` enumerates the ownership of a ERC20 contract. ```go theme={null} type Owner int32 const ( // OWNER_UNSPECIFIED defines an invalid/undefined owner. OWNER_UNSPECIFIED Owner = 0 // OWNER_MODULE erc20 is owned by the erc20 module account. OWNER_MODULE Owner = 1 // EXTERNAL erc20 is owned by an external account. OWNER_EXTERNAL Owner = 2 ) ``` The `Owner` can be checked with the following helper functions: ```go theme={null} // IsNativeCoin returns true if the owner of the ERC20 contract is the // erc20 module account func (tp TokenPair) IsNativeCoin() bool { return tp.ContractOwner == OWNER_MODULE } // IsNativeERC20 returns true if the owner of the ERC20 contract not the // erc20 module account func (tp TokenPair) IsNativeERC20() bool { return tp.ContractOwner == OWNER_EXTERNAL } ``` #### Token Pair by ERC20 and by Denom `TokenPairByERC20` and `TokenPairByDenom` are additional state objects for querying a token pair id. ### Genesis State The `x/erc20` module's `GenesisState` defines the state necessary for initializing the chain from a previous exported height. It contains the module parameters and the registered token pairs : ```go theme={null} // GenesisState defines the module's genesis state. type GenesisState struct { // module parameters Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` // registered token pairs TokenPairs []TokenPair `protobuf:"bytes,2,rep,name=token_pairs,json=tokenPairs,proto3" json:"token_pairs"` } ``` ## State Transitions The erc20 modules allows for two types of registration state transitions. Depending on how token pairs are registered, with `RegisterCoinProposal` or `RegisterERC20Proposal`, there are four possible conversion state transitions. ### Token Pair Registration Both the Cosmos coin and the ERC20 token registration allow for registering several token pairs with one proposal. For simplicity, the following description describes the registration of only one token pair per proposal. #### 1. Register Coin A user registers a native Cosmos Coin. Once the proposal passes (i.e is approved by governance), the ERC20 module uses a factory pattern to deploy an ERC20 token contract representation of the Cosmos Coin. Note that the native HyperPaxeer coin cannot be registered, as any coin including "evm" in its denomination cannot be registered. Instead, the HyperPaxeer token can be converted by Nomand's wrapped HyperPaxeer (WHyperPaxeer) contract. 1. User submits a `RegisterCoinProposal` 2. Validators of the HyperPaxeer Hub vote on the proposal usingΒ `MsgVote`Β and proposal passes 3. If Cosmos coin or IBC voucher exist on the bank module supply, create the [ERC20 token contract](https://github.com/Paxeer-Network/Paxeer-Network/blob/main/contracts/ERC20MinterBurnerDecimals.sol) on the EVM based on the ERC20Mintable ([ERC20Mintable by openzeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20)) interface * Initial supply: 0 * Token details (Name, Symbol, Decimals, etc) are derived from the bank module `Metadata` field on the proposal content. #### 2. Register ERC20 A user registers a ERC20 token contract that is already deployed on the EVM module. Once the proposal passes (i.e. is approved by governance), the ERC20 module creates a Cosmos coin representation of the ERC20 token. 1. User submits a `RegisterERC20Proposal` 2. Validators of the HyperPaxeer chain vote on the proposal usingΒ `MsgVote`Β and proposal passes 3. If ERC-20 contract is deployed on the EVM module, create a bank coinΒ `Metadata`Β from the ERC20 details. ### Token Pair Conversion Conversion of a registered `TokenPair` can be done via: * Cosmos transaction (`ConvertCoin` and `ConvertERC20)` * Ethereum transaction (i.e sending a `MsgEthereumTx` that leverages the EVM hook) #### 1. Registered Coin :::tip πŸ‘‰ **Context:** A `TokenPair` has been created through a `RegisterCoinProposal` governance proposal. The proposal created an `ERC20` contract ([ERC20Mintable by openzeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20)) of the ERC20 token representation of the Coin from the `ModuleAccount`, assigning it as the `owner` of the contract and thus granting it the permission to call the `mint()` and `burnFrom()` methods of the ERC20. ::: ##### Invariants * Only the `ModuleAccount` should have the Minter Role on the ERC20. Otherwise, the user could unilaterally mint an infinite supply of the ERC20 token and then convert them to the native Coin * The user and the `ModuleAccount` (owner) should be the only ones that have the Burn Role for a Cosmos Coin * There shouldn't exist any native Cosmos Coin ERC20 Contract (eg HyperPaxeer, Atom, Osmo ERC20 contracts) that is not owned by the governance * Token/Coin supply is maintained at all times: * Total Coin supply = Coins + Escrowed Coins * Total Token supply = Escrowed Coins = Minted Tokens ##### 1.1 Coin to ERC20 1. User submits `ConvertCoin` Tx 2. Check if conversion is allowed for the pair, sender and recipient * global parameter is enabled * token pair is enabled * sender tokens are not vesting (checked in the bank module) * recipient address is not blacklisted 3. If Coin is a native Cosmos Coin and Token Owner is `ModuleAccount` 1. Escrow Cosmos coin by sending them to the erc20 module account 2. Call `mint()`Β ERC20 tokens from the `ModuleAccount` address and send minted tokens to recipient address 4. Check if token balance increased by amount ##### 1.2 ERC20 to Coin 1. User submits a `ConvertERC20` Tx 2. Check if conversion is allowed for the pair, sender and recipient (see [1.1 Coin to ERC20](#11-coin-to-erc20)) 3. If token is a ERC20 and Token Owner is `ModuleAccount` 1. Call `burnCoins()` on ERC20 to burn ERC20 tokens from the user balance 2. Send Coins (previously escrowed, see [1.1 Coin to ERC20](#11-coin-to-erc20)) from module to the recipient address. 4. Check if * Coin balance increased by amount * Token balance decreased by amount #### 2. Registered ERC20 :::tip πŸ‘‰ **Context:** A `TokenPair` has been created through a `RegisterERC20Proposal` governance proposal. The `ModuleAccount` is not the owner of the contract, so it can't mint new tokens or burn on behalf of the user. The mechanism described below follows the same model as the ICS20 standard, by using escrow & mint / burn & unescrow logic. ::: ##### Invariants * ERC20 Token supply on the EVM runtime is maintained at all times: * Escrowed ERC20 + Minted Cosmos Coin representation of ERC20 = Burned Cosmos Coin representation of ERC20 + Unescrowed ERC20 * Convert 10 ERC20 β†’ Coin, the total supply increases by 10. Mint on Cosmos side, no changes on EVM * Convert 10 Coin β†’ ERC20, the total supply decreases by 10. Burn on Cosmos side , no changes of supply on EVM * Total ERC20 token supply = Non Escrowed Tokens + Escrowed Tokens (on Module account address) * Total Coin supply for the native ERC20 = Escrowed ERC20 Tokens on module account (i.e balance) = Minted Coins ##### 2.1 ERC20 to Coin 1. User submits a `ConvertERC20` Tx 2. Check if conversion is allowed for the pair, sender and recipient (See [1.1 Coin to ERC20](#11-coin-to-erc20)) 3. If token is a ERC20 and Token Owner is **not** `ModuleAccount` 1. Escrow ERC20 token by sending them to the erc20 module account 2. Mint Cosmos coins of the corresponding token pair denomination and send coins to the recipient address 4. Check if * Coin balance increased by amount * Token balance decreased by amount 5. Fail if unexpected `Approval` event found in logs to prevent malicious contract behaviour ##### 2.2 Coin to ERC20 1. User submits `ConvertCoin` Tx 2. Check if conversion is allowed for the pair, sender and recipient 3. If coin is a native Cosmos coin and Token Owner is **not** `ModuleAccount` 1. Escrow Cosmos Coins by sending them to the erc20 module account 2. Unlock escrowed ERC20 from the module address by sending it to the recipient 3. Burn escrowed Cosmos coins 4. Check if token balance increased by amount 5. Fail if unexpected `Approval` event found in logs to prevent malicious contract behaviour ## Transactions This section defines the `sdk.Msg` concrete types that result in the state transitions defined on the previous section. ### `RegisterCoinProposal` A gov `Content` type to register a token pair from a Cosmos Coin. Governance users vote on this proposal and it automatically executes the custom handler forΒ `RegisterCoinProposal`Β when the vote passes. ```go theme={null} type RegisterCoinProposal struct { // title of the proposal Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` // proposal description Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` // metadata slice of the native Cosmos coins Metadata []types.Metadata `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata"` } ``` The proposal content stateless validation fails if: * Title is invalid (length or char) * Description is invalid (length or char) * Metadata is invalid * Name and Symbol are not blank * Base and Display denominations are valid coin denominations * Base and Display denominations are present in the DenomUnit slice * Base denomination has exponent 0 * Denomination units are sorted in ascending order * Denomination units not duplicated ### `RegisterERC20Proposal` A gov `Content` type to register a token pair from an ERC20 Token. Governance users vote on this proposal and it automatically executes the custom handler forΒ `RegisterERC20Proposal`Β when the vote passes. ```go theme={null} type RegisterERC20Proposal struct { // title of the proposal Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` // proposal description Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` // contract addresses of ERC20 tokens Erc20Addresses []string `protobuf:"bytes,3,rep,name=erc20addresses,proto3" json:"erc20addresses,omitempty"` } ``` The proposal Content stateless validation fails if: * Title is invalid (length or char) * Description is invalid (length or char) * ERC20Addresses is invalid ### `MsgConvertCoin` A user broadcastsΒ a `MsgConvertCoin`Β message to convert a Cosmos Coin to a ERC20 token. ```go theme={null} type MsgConvertCoin struct { // Cosmos coin which denomination is registered on erc20 bridge. // The coin amount defines the total ERC20 tokens to convert. Coin types.Coin `protobuf:"bytes,1,opt,name=coin,proto3" json:"coin"` // recipient hex address to receive ERC20 token Receiver string `protobuf:"bytes,2,opt,name=receiver,proto3" json:"receiver,omitempty"` // cosmos bech32 address from the owner of the given ERC20 tokens Sender string `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"` } ``` Message stateless validation fails if: * Coin is invalid (invalid denom or non-positive amount) * Receiver hex address is invalid * Sender bech32 address is invalid ### `MsgConvertERC20` A user broadcastsΒ a `MsgConvertERC20`Β message to convert a ERC20 token to a native Cosmos coin. ```go theme={null} type MsgConvertERC20 struct { // ERC20 token contract address registered on erc20 bridge ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` // amount of ERC20 tokens to mint Amount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"amount"` // bech32 address to receive SDK coins. Receiver string `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` // sender hex address from the owner of the given ERC20 tokens Sender string `protobuf:"bytes,4,opt,name=sender,proto3" json:"sender,omitempty"` } ``` Message stateless validation fails if: * Contract address is invalid * Amount is not positive * Receiver bech32 address is invalid * Sender hex address is invalid ### `ToggleTokenConversionProposal` A gov Content type to toggle the internal conversion of a token pair. ```go theme={null} type ToggleTokenConversionProposal struct { // title of the proposal Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` // proposal description Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` // token identifier can be either the hex contract address of the ERC20 or the // Cosmos base denomination Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"` } ``` ## Hooks The erc20 module implements transaction hooks from the EVM in order to trigger token pair conversion. ### EVM Hooks The EVM hooks allows users to convert ERC20s to Cosmos Coins by sending an Ethereum tx transfer to the module account address. This enables native conversion of tokens via Metamask and EVM-enabled wallets for both token pairs that have been registered through a native Cosmos coin or an ERC20 token. Note that additional coin/token balance checks for sender and receiver to prevent malicious contract behaviour (as performed in the [`ConvertERC20` msg](#state-transitions)) cannot be done here, as the balance prior to the transaction is not available in the hook. #### Registered Coin: ERC20 to Coin 1. User transfers ERC20 tokens to the `ModuleAccount` address to escrow them 2. Check if the ERC20 Token that was transferred from the sender is a native ERC20 or a native Cosmos Coin by looking at the [Ethereum event logs](https://medium.com/mycrypto/understanding-event-logs-on-the-ethereum-blockchain-f4ae7ba50378#:~:text=A%20log%20record%20can%20be,or%20a%20change%20of%20ownership.\&text=Each%20log%20record%20consists%20of,going%20on%20in%20an%20event) 3. If the token contract address corresponds to the ERC20 representation of a native Cosmos Coin 1. Call `burn()` ERC20 method from the `ModuleAccount`. Note that this is the same as 1.2, but since the tokens are already on the ModuleAccount balance, we burn the tokens from the module address instead of calling `burnFrom()`. Also note that we don't need to mint because [1.1 coin to erc20](#state-transitions) escrows the coin 2. Transfer Cosmos Coin to the bech32 account address of the sender hex address #### Registered ERC20: ERC20 to Coin 1. User transfers coins to the`ModuleAccount` to escrow them 2. Check if the ERC20 Token that was transferred is a native ERC20 or a native cosmos coin 3. If the token contract address is a native ERC20 token 1. Mint Cosmos Coin 2. Transfer Cosmos Coin to the bech32 account address of the sender hex ## Events The `x/erc20` module emits the following events: ### Register Coin Proposal | Type | Attribute Key | Attribute Value | | --------------- | --------------- | ----------------- | | `register_coin` | `"cosmos_coin"` | `{denom}` | | `register_coin` | `"erc20_token"` | `{erc20_address}` | ### Register ERC20 Proposal | Type | Attribute Key | Attribute Value | | ---------------- | --------------- | ----------------- | | `register_erc20` | `"cosmos_coin"` | `{denom}` | | `register_erc20` | `"erc20_token"` | `{erc20_address}` | ### Toggle Token Conversion | Type | Attribute Key | Attribute Value | | ------------------------- | --------------- | ----------------- | | `toggle_token_conversion` | `"erc20_token"` | `{erc20_address}` | | `toggle_token_conversion` | `"cosmos_coin"` | `{denom}` | ### Convert Coin | Type | Attribute Key | Attribute Value | | -------------- | --------------- | ---------------------------- | | `convert_coin` | `"sender"` | `{msg.Sender}` | | `convert_coin` | `"receiver"` | `{msg.Receiver}` | | `convert_coin` | `"amount"` | `{msg.Coin.Amount.String()}` | | `convert_coin` | `"cosmos_coin"` | `{denom}` | | `convert_coin` | `"erc20_token"` | `{erc20_address}` | ### Convert ERC20 | Type | Attribute Key | Attribute Value | | --------------- | --------------- | ----------------------- | | `convert_erc20` | `"sender"` | `{msg.Sender}` | | `convert_erc20` | `"receiver"` | `{msg.Receiver}` | | `convert_erc20` | `"amount"` | `{msg.Amount.String()}` | | `convert_erc20` | `"cosmos_coin"` | `{denom}` | | `convert_erc20` | `"erc20_token"` | `{msg.ContractAddress}` | ## Parameters The erc20 module contains the following parameters: | Key | Type | Default Value | | --------------- | ---- | ------------- | | `EnableErc20` | bool | `true` | | `EnableEVMHook` | bool | `true` | ### Enable ERC20 The `EnableErc20` parameter toggles all state transitions in the module. When the parameter is disabled, it will prevent all token pair registration and conversion functionality. ### Enable EVM Hook The `EnableEVMHook` parameter enables the EVM hook to convert an ERC20 token to a Cosmos Coin by transferring the Tokens through a `MsgEthereumTx` to the `ModuleAddress` Ethereum address. ## Clients ### CLI Find below a list of Β `hyperpaxd`Β commands added with the `x/erc20` module. You can obtain the full list by using theΒ `hyperpaxd -h`Β command. A CLI command can look like this: ```bash theme={null} hyperpaxd query erc20 params ``` #### Queries | Command | Subcommand | Description | | --------------- | ------------- | ------------------------------ | | `query` `erc20` | `params` | Get erc20 params | | `query` `erc20` | `token-pair` | Get registered token pair | | `query` `erc20` | `token-pairs` | Get all registered token pairs | #### Transactions | Command | Subcommand | Description | | ------------ | --------------- | ------------------------------ | | `tx` `erc20` | `convert-coin` | Convert a Cosmos Coin to ERC20 | | `tx` `erc20` | `convert-erc20` | Convert a ERC20 to Cosmos Coin | #### Proposals The `tx gov submit-legacy-proposal` commands allow users to query create a proposal using the governance module CLI: **`register-coin`** Allows users to submit a `RegisterCoinProposal`. Submit a proposal to register a Cosmos coin to the erc20 along with an initial deposit. Upon passing, the proposal details must be supplied via a JSON file. ```bash theme={null} hyperpaxd tx gov submit-legacy-proposal register-coin METADATA_FILE [flags] ``` Where METADATA\_FILE contains (example): ```json theme={null} { "metadata": [ { "description": "The native staking and governance token of the Osmosis chain", "denom_units": [ { "denom": "ibc/", "exponent": 0, "aliases": ["ibcuosmo"] }, { "denom": "OSMO", "exponent": 6 } ], "base": "ibc/", "display": "OSMO", "name": "Osmo", "symbol": "OSMO" } ] } ``` **`register-erc20`** Allows users to submit a `RegisterERC20Proposal`. Submit a proposal to register ERC20 tokens along with an initial deposit. To register multiple tokens in one proposal pass them after each other e.g. `register-erc20 `. ```bash theme={null} hyperpaxd tx gov submit-legacy-proposal register-erc20 ERC20_ADDRESS... [flags] ``` **`toggle-token-conversion`** Allows users to submit a `ToggleTokenConversionProposal`. ```bash theme={null} hyperpaxd tx gov submit-legacy-proposal toggle-token-conversion TOKEN [flags] ``` **Update Params** Allows users to submit a `MsgUpdateParams` with the desired changes on the `x/erc20` module parameters. To do this, you will have to provide a JSON file with the correspondiong message in the `submit-proposal` command. For more information on how to draft a proposal, refer to the [Drafting a proposal section](../Paxeer-Network-cli/proposal-draft.md). ```bash theme={null} hyperpaxd tx gov submit-proposal proposal.json [flags] ``` ### gRPC #### Queries | Verb | Method | Description | | ------ | --------------------------------------- | ------------------------------ | | `gRPC` | `HyperPaxeer.erc20.v1.Query/Params` | Get erc20 params | | `gRPC` | `HyperPaxeer.erc20.v1.Query/TokenPair` | Get registered token pair | | `gRPC` | `HyperPaxeer.erc20.v1.Query/TokenPairs` | Get all registered token pairs | | `GET` | `/Paxeer-Network/erc20/v1/params` | Get erc20 params | | `GET` | `/Paxeer-Network/erc20/v1/token_pair` | Get registered token pair | | `GET` | `/Paxeer-Network/erc20/v1/token_pairs` | Get all registered token pairs | #### Transactions | Verb | Method | Description | | ------ | ------------------------------------------- | ------------------------------ | | `gRPC` | `HyperPaxeer.erc20.v1.Msg/ConvertCoin` | Convert a Cosmos Coin to ERC20 | | `gRPC` | `HyperPaxeer.erc20.v1.Msg/ConvertERC20` | Convert a ERC20 to Cosmos Coin | | `GET` | `/Paxeer-Network/erc20/v1/tx/convert_coin` | Convert a Cosmos Coin to ERC20 | | `GET` | `/Paxeer-Network/erc20/v1/tx/convert_erc20` | Convert a ERC20 to Cosmos Coin | # Evm Source: https://sidiorresearchlabs.mintlify.app/protocol/modules/evm # `evm` ## Abstract This document defines the specification of the Ethereum Virtual Machine (EVM) as a Cosmos SDK module. Since the introduction of Ethereum in 2015, the ability to control digital assets through [**smart contracts**](https://www.fon.hum.uva.nl/rob/Courses/InformationInSpeech/CDROM/Literature/LOTwinterschool2006/szabo.best.vwh.net/idea.html) has attracted a large community of developers to build decentralized applications on the Ethereum Virtual Machine (EVM). This community is continuously creating extensive tooling and introducing standards, which are further increasing the adoption rate of EVM compatible technology. The growth of EVM-based chains (e.g. Ethereum), however, has uncovered several scalability challenges that are often referred to as the [trilemma of decentralization, security, and scalability](https://vitalik.eth.limo/general/2021/04/07/sharding.html). Developers are frustrated by high gas fees, slow transaction speed & throughput, and chain-specific governance that can only undergo slow change because of its wide range of deployed applications. A solution is required that eliminates these concerns for developers, who build applications within a familiar EVM environment. The `x/evm` module provides this EVM familiarity on a scalable, high-throughput Proof-of-Stake blockchain. It is built as a [Cosmos SDK module](https://docs.cosmos.network/main/build/building-modules/intro) which allows for the deployment of smart contracts, interaction with the EVM state machine (state transitions), and the use of EVM tooling. It can be used on Cosmos application-specific blockchains, which alleviate the aforementioned concerns through high transaction throughput via [Tendermint Core](https://github.com/tendermint/tendermint), fast transaction finality, and horizontal scalability via [IBC](https://ibcprotocol.org/). The `x/evm` module is part of the HyperPaxeer EVM stack, forked from the hyperpaxeer library. ## Contents 1. **[Concepts](#concepts)** 2. **[State](#state)** 3. **[State Transitions](#state-transitions)** 4. **[Transactions](#transactions)** 5. **[ABCI](#abci)** 6. **[Hooks](#hooks)** 7. **[Events](#events)** 8. **[Parameters](#parameters)** 9. **[Client](#client)** ## Module Architecture > **NOTE:**: If you're not familiar with the overall module structure from > the SDK modules, please check this [document](https://docs.cosmos.network/main/build/building-modules/structure) as > prerequisite reading. ```shell theme={null} evm/ β”œβ”€β”€ client β”‚ └── cli β”‚ β”œβ”€β”€ query.go # CLI query commands for the module β”‚ Β Β  └── tx.go # CLI transaction commands for the module β”œβ”€β”€ keeper β”‚ β”œβ”€β”€ keeper.go # ABCI BeginBlock and EndBlock logic β”‚ β”œβ”€β”€ keeper.go # Store keeper that handles the business logic of the module and has access to a specific subtree of the state tree. β”‚ β”œβ”€β”€ params.go # Parameter getter and setter β”‚ β”œβ”€β”€ querier.go # State query functions β”‚ └── statedb.go # Functions from types/statedb with a passed in sdk.Context β”œβ”€β”€ types β”‚Β Β  β”œβ”€β”€ chain_config.go β”‚Β Β  β”œβ”€β”€ codec.go # Type registration for encoding β”‚Β Β  β”œβ”€β”€ errors.go # Module-specific errors β”‚Β Β  β”œβ”€β”€ events.go # Events exposed to the Tendermint PubSub/Websocket β”‚Β Β  β”œβ”€β”€ genesis.go # Genesis state for the module β”‚Β Β  β”œβ”€β”€ journal.go # Ethereum Journal of state transitions β”‚Β Β  β”œβ”€β”€ keys.go # Store keys and utility functions β”‚Β Β  β”œβ”€β”€ logs.go # Types for persisting Ethereum tx logs on state after chain upgrades β”‚Β Β  β”œβ”€β”€ msg.go # EVM module transaction messages β”‚Β Β  β”œβ”€β”€ params.go # Module parameters that can be customized with governance parameter change proposals β”‚Β Β  β”œβ”€β”€ state_object.go # EVM state object β”‚Β Β  β”œβ”€β”€ statedb.go # Implementation of the StateDb interface β”‚Β Β  β”œβ”€β”€ storage.go # Implementation of the Ethereum state storage map using arrays to prevent non-determinism β”‚Β Β  └── tx_data.go # Ethereum transaction data types β”œβ”€β”€ genesis.go # ABCI InitGenesis and ExportGenesis functionality β”œβ”€β”€ handler.go # Message routing └── module.go # Module setup for the module manager ``` ## Concepts ### EVM The Ethereum Virtual Machine (EVM) is a computation engine which can be thought of as one single entity maintained by thousands of connected computers (nodes) running an Ethereum client. As a virtual machine ([VM](https://en.wikipedia.org/wiki/Virtual_machine)), the EVM is responsible for computing changes to the state deterministically regardless of its environment (hardware and OS). This means that every node has to get the exact same result given an identical starting state and transaction (tx). The EVM is considered to be the part of the Ethereum protocol that handles the deployment and execution of [smart contracts](https://ethereum.org/en/developers/docs/smart-contracts/). To make a clear distinction: * The Ethereum protocol describes a blockchain, in which all Ethereum accounts and smart contracts live. It has only one canonical state (a data structure, which keeps allΒ accounts) at any given block in the chain. * The EVM, however, is the [state machine](https://en.wikipedia.org/wiki/Finite-state_machine) that defines the rules for computing a new valid state from block to block. It is an isolated runtime, which means that code running inside the EVM has no access to network, filesystem, or other processes (not external APIs). The `x/evm` module implements the EVM as a Cosmos SDK module. It allows users to interact with the EVM by submitting Ethereum txs and executing their containing messages on the given state to evoke a state transition. #### State The Ethereum state is a data structure, implemented as a [Merkle Patricia Tree](https://en.wikipedia.org/wiki/Merkle_tree), that keeps all accounts on the chain. The EVM makes changes to this data structure resulting in a new state with a different state root. Ethereum can therefore be seen as a state chain that transitions from one state to another by executing transactions in a block using the EVM. A new block of txs can be described through its block header (parent hash, block number, time stamp, nonce, receipts,...). #### Accounts There are two types of accounts that can be stored in state at a given address: * **Externally Owned Account (EOA)**: Has nonce (tx counter) and balance * **Smart Contract**: Has nonce, balance, (immutable) code hash, storage root (another Merkle Patricia Trie) Smart contracts are just like regular accounts on the blockchain, which additionally store executable code in an Ethereum-specific binary format, known as **EVM bytecode**. They are typically written in an Ethereum high level language, such as Solidity, which is compiled down to EVM bytecode and deployed on the blockchain by submitting a transaction using an Ethereum client. #### Architecture The EVM operates as a stack-based machine. It's main architecture components consist of: * Virtual ROM: contract code is pulled into this read only memory when processing txs * Machine state (volatile): changes as the EVM runs and is wiped clean after processing each tx * Program counter (PC) * Gas: keeps track of how much gas is used * Stack and Memory: compute state changes * Access to account storage (persistent) #### State Transitions with Smart Contracts Typically smart contracts expose a public ABI, which is a list of supported ways a user can interact with a contract. To interact with a contract and invoke a state transition, a user will submit a tx carrying any amount of gas and a data payload formatted according to the ABI, specifying the type of interaction and any additional parameters. When the tx is received, the EVM executes the smart contracts' EVM bytecode using the tx payload. #### Executing EVM bytecode A contract's EVM bytecode consists of basic operations (add, multiply, store, etc...), called **Opcodes**. Each Opcode execution requires gas that needs to be paid with the tx. The EVM is therefore considered quasi-turing complete, as it allows any arbitrary computation, but the amount of computations during a contract execution is limited to the amount of gas provided in the tx. Each Opcode's [**gas cost**](https://www.evm.codes/) reflects the cost of running these operations on actual computer hardware (e.g. `ADD = 3gas` and `SSTORE = 100gas`). To calculate the gas consumption of a tx, the gas cost is multiplied by the **gas price**, which can change depending on the demand of the network at the time. If the network is under heavy load, you might have to pay a higher gas price to get your tx executed. If the gas limit is hit (out of gas exception) no changes to the Ethereum state are applied, except that the sender's nonce increments and their balance goes down to pay for wasting the EVM's time. Smart contracts can also call other smart contracts. Each call to a new contract creates a new instance of the EVM (including a new stack and memory). Each call passes the sandbox state to the next EVM. If the gas runs out, all state changes are discarded. Otherwise, they are kept. For further reading, please refer to: * [EVM](https://eth.wiki/concepts/evm/evm) * [EVM Architecture](https://cypherpunks-core.github.io/ethereumbook/13evm.html#evm_architecture) * [What is Ethereum](https://ethdocs.org/en/latest/introduction/what-is-ethereum.html#what-is-ethereum) * [Opcodes](https://www.ethervm.io/) ### HyperPaxeer as Geth implementation HyperPaxeer contains an implementation of the [Ethereum protocol in Golang](https://geth.ethereum.org/docs/getting-started) (Geth) as a Cosmos SDK module. Geth includes an implementation of the EVM to compute state transitions. Have a look at the [go-ethereum source code](https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go) to see how the EVM opcodes are implemented. Just as Geth can be run as an Ethereum node, HyperPaxeer can be run as a node to compute state transitions with the EVM. HyperPaxeer supports Geth's standard Ethereum JSON-RPC APIs in order to be Web3 and EVM compatible. #### JSON-RPC JSON-RPC is a stateless, lightweight remote procedure call (RPC) protocol. Primarily this specification defines several data structures and the rules around their processing. It is transport agnostic in that the concepts can be used within the same process, over sockets, over HTTP, or in many various message passing environments. It uses JSON (RFC 4627) as a data format. ##### JSON-RPC Example: `eth_call` The JSON-RPC method [`eth_call`](https://docs.paxeer.app/develop/api/ethereum-json-rpc/methods#eth-call) allows you to execute messages against contracts. Usually, you need to send a transaction to a Geth node to include it in the mempool, then nodes gossip between each other and eventually the transaction is included in a block and gets executed. `eth_call` however lets you send data to a contract and see what happens without committing a transaction. In the Geth implementation, calling the endpoint roughly goes through the following steps: 1. The `eth_call` request is transformed to call the `func (s *PublicBlockchainAPI) Call()` function using the `eth` namespace 2. [`Call()`](https://github.com/ethereum/go-ethereum/blob/master/internal/ethapi/api.go#L982) is given the transaction arguments, the block to call against and optional arguments that modify the state to call against. It then calls `DoCall()`. 3. [`DoCall()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/internal/ethapi/api.go#L891) transforms the arguments into a `ethtypes.message`, instantiates an EVM and applies the message with `core.ApplyMessage` 4. [`ApplyMessage()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/core/state_transition.go#L180) calls the state transition `TransitionDb()` 5. [`TransitionDb()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/core/state_transition.go#L275) either `Create()`s a new contract or `Call()`s a contract 6. [`evm.Call()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/core/vm/evm.go#L168) runs the interpreter `evm.interpreter.Run()` to execute the message. If the execution fails, the state is reverted to a snapshot taken before the execution and gas is consumed. 7. [`Run()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/core/vm/interpreter.go#L116) performs a loop to execute the opcodes. The HyperPaxeer implementation is similar and makes use of the gRPC query client which is included in the Cosmos SDK: 1. `eth_call` request is transformed to call the `func (e *PublicAPI) Call` function using the `eth` namespace 2. [`Call()`](https://github.com/paxeer-network/hyperpaxeer/blob/main/rpc/namespaces/ethereum/eth/api.go#L639) calls `doCall()` 3. [`doCall()`](https://github.com/paxeer-network/hyperpaxeer/blob/main/rpc/namespaces/ethereum/eth/api.go#L656) transforms the arguments into a `EthCallRequest` and calls `EthCall()` using the query client of the evm module. 4. [`EthCall()`](https://github.com/paxeer-network/hyperpaxeer/blob/main/x/evm/keeper/grpc_query.go#L212) transforms the arguments into a `ethtypes.message` and calls \`ApplyMessageWithConfig() 5. [`ApplyMessageWithConfig()`](https://github.com/paxeer-network/hyperpaxeer/blob/d5598932a7f06158b7a5e3aa031bbc94eaaae32c/x/evm/keeper/state_transition.go#L341) instantiates an EVM and either `Create()`s a new contract or `Call()`s a contract using the Geth implementation. #### StateDB The `StateDB` interface from [go-ethereum](https://github.com/ethereum/go-ethereum/blob/master/core/vm/interface.go) represents an EVM database for full state querying. EVM state transitions are enabled by this interface, which in the `x/evm` module is implemented by the `Keeper`. This implementation of this interface is what makes HyperPaxeer EVM compatible. ### Consensus Engine The application using the `x/evm` module interacts with the Tendermint Core Consensus Engine over an Application Blockchain Interface (ABCI). Together, the application and Tendermint Core form the programs that run a complete blockchain and combine business logic with decentralized data storage. Ethereum transactions which are submitted to the `x/evm` module take part in this consensus process before being executed and changing the application state. We encourage to understand the basics of the [Tendermint consensus engine](https://docs.tendermint.com/main/introduction/what-is-tendermint.html#intro-to-abci) in order to understand state transitions in detail. ### Transaction Logs On every `x/evm` transaction, the result contains the Ethereum `Log`s from the state machine execution that are used by the JSON-RPC Web3 server for filter querying and for processing the EVM Hooks. The tx logs are stored in the transient store during tx execution and then emitted through cosmos events after the transaction has been processed. They can be queried via gRPC and JSON-RPC. ### Block Bloom Bloom is the bloom filter value in bytes for each block that can be used for filter queries. The block bloom value is stored in the transient store and then emitted through a cosmos event during `EndBlock` processing. They can be queried via gRPC and JSON-RPC. :::tip πŸ‘‰ **Note**: Since they are not stored on state, Transaction Logs and Block Blooms are not persisted after upgrades. A user must use an archival node after upgrades in order to obtain legacy chain events. ::: ## State This section gives you an overview of the objects stored in the `x/evm` module state, functionalities that are derived from the go-ethereum `StateDB` interface, and its implementation through the Keeper as well as the state implementation at genesis. ### State Objects The `x/evm` module keeps the following objects in state: #### State | | Description | Key | Value | Store | | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------- | --------- | | Code | Smart contract bytecode | `[]byte{1} + []byte(address)` | `[]byte{code}` | KV | | Storage | Smart contract storage | `[]byte{2} + [32]byte{key}` | `[32]byte(value)` | KV | | Block Bloom | Block bloom filter, used to accumulate the bloom filter of current block, emitted to events at end blocker. | `[]byte{1} + []byte(tx.Hash)` | `protobuf([]Log)` | Transient | | Tx Index | Index of current transaction in current block. | `[]byte{2}` | `BigEndian(uint64)` | Transient | | Log Size | Number of the logs emitted so far in current block. Used to decide the log index of following logs. | `[]byte{3}` | `BigEndian(uint64)` | Transient | | Gas Used | Amount of gas used by ethereum messages of current cosmos-sdk tx, it's necessary when cosmos-sdk tx contains multiple ethereum messages. | `[]byte{4}` | `BigEndian(uint64)` | Transient | ### StateDB The `StateDB` interface is implemented by the `StateDB` in the `x/evm/statedb` module to represent an EVM database for full state querying of both contracts and accounts. Within the Ethereum protocol, `StateDB`s are used to store anything within the IAVL tree and take care of caching and storing nested states. ```go theme={null} // github.com/ethereum/go-ethereum/core/vm/interface.go type StateDB interface { CreateAccount(common.Address) SubBalance(common.Address, *big.Int) AddBalance(common.Address, *big.Int) GetBalance(common.Address) *big.Int GetNonce(common.Address) uint64 SetNonce(common.Address, uint64) GetCodeHash(common.Address) common.Hash GetCode(common.Address) []byte SetCode(common.Address, []byte) GetCodeSize(common.Address) int AddRefund(uint64) SubRefund(uint64) GetRefund() uint64 GetCommittedState(common.Address, common.Hash) common.Hash GetState(common.Address, common.Hash) common.Hash SetState(common.Address, common.Hash, common.Hash) Suicide(common.Address) bool HasSuicided(common.Address) bool // Exist reports whether the given account exists in state. // Notably this should also return true for suicided accounts. Exist(common.Address) bool // Empty returns whether the given account is empty. Empty // is defined according to EIP161 (balance = nonce = code = 0). Empty(common.Address) bool PrepareAccessList(sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) AddressInAccessList(addr common.Address) bool SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool) // AddAddressToAccessList adds the given address to the access list. This operation is safe to perform // even if the feature/fork is not active yet AddAddressToAccessList(addr common.Address) // AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform // even if the feature/fork is not active yet AddSlotToAccessList(addr common.Address, slot common.Hash) RevertToSnapshot(int) Snapshot() int AddLog(*types.Log) AddPreimage(common.Hash, []byte) ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error } ``` The `StateDB` in the `x/evm` provides the following functionalities: #### CRUD of Ethereum accounts You can create `EthAccount` instances from the provided address and set the value to store on the `AccountKeeper`with `createAccount()`. If an account with the given address already exists, this function also resets any preexisting code and storage associated with that address. An account's coin balance can be is managed through the `BankKeeper` and can be read with `GetBalance()` and updated with `AddBalance()` and `SubBalance()`. * `GetBalance()` returns the EVM denomination balance of the provided address. The denomination is obtained from the module parameters. * `AddBalance()` adds the given amount to the address balance coin by minting new coins and transferring them to the address. The coin denomination is obtained from the module parameters. * `SubBalance()` subtracts the given amount from the address balance by transferring the coins to an escrow account and then burning them. The coin denomination is obtained from the module parameters. This function performs a no-op if the amount is negative or the user doesn't have enough funds for the transfer. The nonce (or transaction sequence) can be obtained from the Account `Sequence` via the auth module `AccountKeeper`. * `GetNonce()` retrieves the account with the given address and returns the tx sequence (i.e nonce). The function performs a no-op if the account is not found. * `SetNonce()` sets the given nonce as the sequence of the address' account. If the account doesn't exist, a new one will be created from the address. The smart contract bytecode containing arbitrary contract logic is stored on the `EVMKeeper` and it can be queried with `GetCodeHash()` ,`GetCode()` & `GetCodeSize()`and updated with `SetCode()`. * `GetCodeHash()` fetches the account from the store and returns its code hash. If the account doesn't exist or is not an EthAccount type, it returns the empty code hash value. * `GetCode()` returns the code byte array associated with the given address. If the code hash from the account is empty, this function returns nil. * `SetCode()` stores the code byte array to the application KVStore and sets the code hash to the given account. The code is deleted from the store if it is empty. * `GetCodeSize()` returns the size of the contract code associated with this object, or zero if none. Gas refunded needs to be tracked and stored in a separate variable in order to add it subtract/add it from/to the gas used value after the EVM execution has finalized. The refund value is cleared on every transaction and at the end of every block. * `AddRefund()` adds the given amount of gas to the in-memory refund value. * `SubRefund()` subtracts the given amount of gas from the in-memory refund value. This function will panic if gas amount is greater than the current refund. * `GetRefund()` returns the amount of gas available for return after the tx execution finalizes. This value is reset to 0 on every transaction. The state is stored on the `EVMKeeper`. It can be queried with `GetCommittedState()`, `GetState()` and updated with `SetState()`. * `GetCommittedState()` returns the value set in store for the given key hash. If the key is not registered this function returns the empty hash. * `GetState()` returns the in-memory dirty state for the given key hash, if not exist load the committed value from KVStore. * `SetState()` sets the given hashes (key, value) to the state. If the value hash is empty, this function deletes the key from the state, the new value is kept in dirty state at first, and will be committed to KVStore in the end. Accounts can also be set to a suicide state. When a contract commits suicide, the account is marked as suicided, when committing the code, storage and account are deleted (from the next block and forward). * `Suicide()` marks the given account as suicided and clears the account balance of the EVM tokens. * `HasSuicided()` queries the in-memory flag to check if the account has been marked as suicided in the current transaction. Accounts that are suicided will be returned as non-nil during queries and "cleared" after the block has been committed. To check account existence use `Exist()` and `Empty()`. * `Exist()` returns true if the given account exists in store or if it has been marked as suicided. * `Empty()` returns true if the address meets the following conditions: * nonce is 0 * balance amount for evm denom is 0 * account code hash is empty #### EIP2930 functionality Supports a transaction type that contains an [access list](https://eips.ethereum.org/EIPS/eip-2930), a list of addresses and storage keys, that the transaction plans to access. The access list state is kept in memory and discarded after the transaction committed. * `PrepareAccessList()` handles the preparatory steps for executing a state transition in regard to both EIP-2929 and EIP-2930. This method should only be called if Yolov3/Berlin/2929+2930 is applicable at the current number. * Add sender to access list (EIP-2929) * Add destination to access list (EIP-2929) * Add precompiles to access list (EIP-2929) * Add the contents of the optional tx access list (EIP-2930) * `AddressInAccessList()` returns true if the address is registered. * `SlotInAccessList()` checks if the address and the slots are registered. * `AddAddressToAccessList()` adds the given address to the access list. If the address is already in the access list, this function performs a no-op. * `AddSlotToAccessList()` adds the given (address, slot) to the access list. If the address and slot are already in the access list, this function performs a no-op. #### Snapshot state and Revert functionality The EVM uses state-reverting exceptions to handle errors. Such an exception will undo all changes made to the state in the current call (and all its sub-calls), and the caller could handle the error and don't propagate. You can use `Snapshot()` to identify the current state with a revision and revert the state to a given revision with `RevertToSnapshot()` to support this feature. * `Snapshot()` creates a new snapshot and returns the identifier. * `RevertToSnapshot(rev)` undo all the modifications up to the snapshot identified as `rev`. HyperPaxeer adapted the [go-ethereum journal implementation](https://github.com/ethereum/go-ethereum/blob/master/core/state/journal.go#L39) to support this, it uses a list of journal logs to record all the state modification operations done so far, snapshot is consists of a unique id and an index in the log list, and to revert to a snapshot it just undoes the journal logs after the snapshot index in reversed order. #### Ethereum Transaction logs With `AddLog()` you can append the given Ethereum `Log` to the list of logs associated with the transaction hash kept in the current state. This function also fills in the tx hash, block hash, tx index and log index fields before setting the log to store. ### Keeper The EVM module `Keeper` grants access to the EVM module state and implements `statedb.Keeper` interface to support the `StateDB` implementation. The Keeper contains a store key that allows the DB to write to a concrete subtree of the multistore that is only accessible by the EVM module. Instead of using a trie and database for querying and persistence (the `StateDB` implementation), HyperPaxeer uses the Cosmos `KVStore` (key-value store) and Cosmos SDK `Keeper` to facilitate state transitions. To support the interface functionality, it imports 4 module Keepers: * `auth`: CRUD accounts * `bank`: accounting (supply) and CRUD of balances * `staking`: query historical headers * `fee market`: EIP-1559 base fee for processing `DynamicFeeTx` after the `London` hard fork has been activated on the `ChainConfig` parameters ```go theme={null} type Keeper struct { // Protobuf codec cdc codec.BinaryCodec // Store key required for the EVM Prefix KVStore. It is required by: // - storing account's Storage State // - storing account's Code // - storing Bloom filters by block height. Needed for the Web3 API. // For the full list, check the module specification storeKey sdk.StoreKey // key to access the transient store, which is reset on every block during Commit transientKey sdk.StoreKey // module specific parameter space that can be configured through governance paramSpace paramtypes.Subspace // access to account state accountKeeper types.AccountKeeper // update balance and accounting operations with coins bankKeeper types.BankKeeper // access historical headers for EVM state transition execution stakingKeeper types.StakingKeeper // fetch EIP1559 base fee and parameters feeMarketKeeper types.FeeMarketKeeper // chain ID number obtained from the context's chain id eip155ChainID *big.Int // Tracer used to collect execution traces from the EVM transaction execution tracer string // trace EVM state transition execution. This value is obtained from the `--trace` flag. // For more info check https://geth.ethereum.org/docs/dapp/tracing debug bool // EVM Hooks for tx post-processing hooks types.EvmHooks } ``` ### Genesis State The `x/evm` module `GenesisState` defines the state necessary for initializing the chain from a previous exported height. It contains the `GenesisAccounts` and the module parameters ```go theme={null} type GenesisState struct { // accounts is an array containing the ethereum genesis accounts. Accounts []GenesisAccount `protobuf:"bytes,1,rep,name=accounts,proto3" json:"accounts"` // params defines all the parameters of the module. Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` } ``` ### Genesis Accounts The `GenesisAccount` type corresponds to an adaptation of the Ethereum `GenesisAccount` type. It defines an account to be initialized in the genesis state. Its main difference is that the one on HyperPaxeer uses a custom `Storage` type that uses a slice instead of maps for the evm `State` (due to non-determinism), and that it doesn't contain the private key field. It is also important to note that since the `auth` module on the Cosmos SDK manages the account state, the `Address` field must correspond to an existing `EthAccount` that is stored in the `auth`'s module `Keeper` (i.e `AccountKeeper`). Addresses use the **[EIP55](https://eips.ethereum.org/EIPS/eip-55)** hex **[format](https://docs.paxeer.app/protocol/concepts/accounts#address-formats-for-clients)** on `genesis.json`. ```go theme={null} type GenesisAccount struct { // address defines an ethereum hex formated address of an account Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // code defines the hex bytes of the account code. Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"` // storage defines the set of state key values for the account. Storage Storage `protobuf:"bytes,3,rep,name=storage,proto3,castrepeated=Storage" json:"storage"` } ``` ## State Transitions The `x/evm` module allows for users to submit Ethereum transactions (`Tx`) and execute their containing messages to evoke state transitions on the given state. Users submit transactions client-side to broadcast it to the network. When the transaction is included in a block during consensus, it is executed server-side. We highly recommend to understand the basics of the [Tendermint consensus engine](https://docs.tendermint.com/main/introduction/what-is-tendermint.html#intro-to-abci) to understand the State Transitions in detail. ### Client-Side :::tip πŸ‘‰ This is based on the `eth_sendTransaction` JSON-RPC ::: 1. A user submits a transaction via one of the available JSON-RPC endpoints using an Ethereum-compatible client or wallet (eg Metamask, WalletConnect, Ledger, etc): a. eth (public) namespace: * `eth_sendTransaction` * `eth_sendRawTransaction` b. personal (private) namespace: * `personal_sendTransaction` 2. An instance of `MsgEthereumTx` is created after populating the RPC transaction using `SetTxDefaults` to fill missing tx arguments with default values 3. The `Tx` fields are validated (stateless) using `ValidateBasic()` 4. The `Tx` is **signed** using the key associated with the sender address and the latest ethereum hard fork (`London`, `Berlin`, etc) from the `ChainConfig` 5. The `Tx` is **built** from the msg fields using the Cosmos Config builder 6. The `Tx` is **broadcast** in [sync mode](https://docs.cosmos.network/main/user/run-node/txs#broadcasting-a-transaction) to ensure to wait for a [`CheckTx`](https://docs.tendermint.com/main/introduction/what-is-tendermint.html#intro-to-abci) execution response. Transactions are validated by the application using `CheckTx()`, before being added to the mempool of the consensus engine. 7. JSON-RPC user receives a response with the [`RLP`](https://eth.wiki/en/fundamentals/rlp) hash of the transaction fields. This hash is different from the default hash used by SDK Transactions that calculates the `sha256` hash of the transaction bytes. ### Server-Side Once a block (containing the `Tx`) has been committed during consensus, it is applied to the application in a series of ABCI msgs server-side. Each `Tx` is handled by the application by calling [`RunTx`](https://docs.cosmos.network/main/learn/advanced/baseapp). After a stateless validation on eachΒ `sdk.Msg` in theΒ `Tx`, the `AnteHandler` confirms whether the `Tx` is an Ethereum or SDK transaction. As an Ethereum transaction it's containing msgs are then handled by the `x/evm` module to update the application's state. #### AnteHandler The `anteHandler` is run for every transaction. It checks if the `Tx` is an Ethereum transaction and routes it to an internal ante handler. Here, `Tx`s are handled using EthereumTx extension options to process them differently than normal Cosmos SDK transactions. The `antehandler` runs through a series of options and their `AnteHandle` functions for each `Tx`: * `EthSetUpContextDecorator()` is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption by setting the gas meter to infinite * `EthValidateBasicDecorator(evmKeeper)` validates the fields of an Ethereum type Cosmos `Tx` msg * `EthSigVerificationDecorator(evmKeeper)` validates that the registered chain id is the same as the one on the message, and that the signer address matches the one defined on the message. It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work. Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user won't see the error message. * `EthAccountVerificationDecorator(ak, bankKeeper, evmKeeper)` will verify, that the sender balance is greater than the total transaction cost. The account will be set to store if it doesn't exist, i.e cannot be found on store. This AnteHandler decorator will fail if: * any of the msgs is not a MsgEthereumTx * from address is empty * account balance is lower than the transaction cost * `EthNonceVerificationDecorator(ak)` validates that the transaction nonces are valid and equivalent to the sender account’s current nonce. * `EthGasConsumeDecorator(evmKeeper)` validates that the Ethereum tx message has enough to cover intrinsic gas (during CheckTx only) and that the sender has enough balance to pay for the gas cost. Intrinsic gas for a transaction is the amount of gas that the transaction uses before the transaction is executed. The gas is a constant value plus any cost incurred by additional bytes of data supplied with the transaction. This AnteHandler decorator will fail if: * the transaction contains more than one message * the message is not a MsgEthereumTx * sender account cannot be found * transaction's gas limit is lower than the intrinsic gas * user doesn't have enough balance to deduct the transaction fees (gas\_limit \* gas\_price) * transaction or block gas meter runs out of gas * `CanTransferDecorator(evmKeeper, feeMarketKeeper)` creates an EVM from the message and calls the BlockContext CanTransfer function to see if the address can execute the transaction. * `EthIncrementSenderSequenceDecorator(ak)` handles incrementing the sequence of the signer (i.e sender). If the transaction is a contract creation, the nonce will be incremented during the transaction execution and not within this AnteHandler decorator. The options `authante.NewMempoolFeeDecorator()`, `authante.NewTxTimeoutHeightDecorator()` and `authante.NewValidateMemoDecorator(ak)` are the same as for a Cosmos `Tx`. ClickΒ [here](https://docs.cosmos.network/main/learn/beginner/gas-fees.html#antehandler)Β for more on theΒ `anteHandler`. #### EVM module After authentication through the `antehandler`, each `sdk.Msg` (in this case `MsgEthereumTx`) in the `Tx` is delivered to the Msg Handler in the `x/evm` module and runs through the following the steps: 1. Convert `Msg` to an ethereum `Tx` type 2. Apply `Tx` with `EVMConfig` and attempt to perform a state transition, that will only be persisted (committed) to the underlying KVStore if the transaction does not fail: 1. Confirm that `EVMConfig` is created 2. Create the ethereum signer using chain config value from `EVMConfig` 3. Set the ethereum transaction hash to the (impermanent) transient store so that it's also available on the StateDB functions 4. Generate a new EVM instance 5. Confirm that EVM params for contract creation (`EnableCreate`) and contract execution (`EnableCall`) are enabled 6. Apply message. If `To` address is `nil`, create new contract using code as deployment code. Else call contract at given address with the given input as parameters 7. Calculate gas used by the evm operation 3. If `Tx` applied successfully 1. Execute EVM `Tx` postprocessing hooks. If hooks return error, revert the whole `Tx` 2. Refund gas according to Ethereum gas accounting rules 3. Update block bloom filter value using the logs generated from the tx 4. Emit SDK events for the transaction fields and tx logs ## Transactions This section defines theΒ `sdk.Msg`Β concrete types that result in the state transitions defined on the previous section. ## `MsgEthereumTx` An EVM state transition can be achieved by using the `MsgEthereumTx`. This message encapsulates an Ethereum transaction data (`TxData`) as a `sdk.Msg`. It contains the necessary transaction data fields. Note, that the `MsgEthereumTx` implements both the [`sdk.Msg`](https://github.com/cosmos/cosmos-sdk/blob/v0.39.2/types/tx_msg.go#L7-L29) and [`sdk.Tx`](https://github.com/cosmos/cosmos-sdk/blob/v0.39.2/types/tx_msg.go#L33-L41) interfaces. Normally, SDK messages only implement the former, while the latter is a group of messages bundled together. ```go theme={null} type MsgEthereumTx struct { // inner transaction data Data *types.Any `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` // DEPRECATED: encoded storage size of the transaction Size_ float64 `protobuf:"fixed64,2,opt,name=size,proto3" json:"-"` // transaction hash in hex format Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty" rlp:"-"` // ethereum signer address in hex format. This address value is checked // against the address derived from the signature (V, R, S) using the // secp256k1 elliptic curve From string `protobuf:"bytes,4,opt,name=from,proto3" json:"from,omitempty"` } ``` This message field validation is expected to fail if: * `From` field is defined and the address is invalid * `TxData` stateless validation fails The transaction execution is expected to fail if: * Any of the custom `AnteHandler` Ethereum decorators checks fail: * Minimum gas amount requirements for transaction * Tx sender account doesn't exist or hasn't enough balance for fees * Account sequence doesn't match the transaction `Data.AccountNonce` * Message signature verification fails * EVM contract creation (i.e `evm.Create`) fails, or `evm.Call` fails #### Conversion The `MsgEthreumTx` can be converted to the go-ethereum `Transaction` and `Message` types in order to create and call evm contracts. ```go theme={null} // AsTransaction creates an Ethereum Transaction type from the msg fields func (msg MsgEthereumTx) AsTransaction() *ethtypes.Transaction { txData, err := UnpackTxData(msg.Data) if err != nil { return nil } return ethtypes.NewTx(txData.AsEthereumData()) } // AsMessage returns the transaction as a core.Message. func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) { msg := Message{ nonce: tx.Nonce(), gasLimit: tx.Gas(), gasPrice: new(big.Int).Set(tx.GasPrice()), gasFeeCap: new(big.Int).Set(tx.GasFeeCap()), gasTipCap: new(big.Int).Set(tx.GasTipCap()), to: tx.To(), amount: tx.Value(), data: tx.Data(), accessList: tx.AccessList(), isFake: false, } // If baseFee provided, set gasPrice to effectiveGasPrice. if baseFee != nil { msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.gasTipCap, baseFee), msg.gasFeeCap) } var err error msg.from, err = Sender(s, tx) return msg, err } ``` #### Signing In order for the signature verification to be valid, the `TxData` must contain the `v | r | s` values from the `Signer`. Sign calculates a secp256k1 ECDSA signature and signs the transaction. It takes a keyring signer and the chainID to sign an Ethereum transaction according to EIP-155 standard. This method mutates the transaction as it populates the V, R, S fields of the Transaction's Signature. The function will fail if the sender address is not defined for the msg or if the sender is not registered on the keyring. ```go theme={null} // Sign calculates a secp256k1 ECDSA signature and signs the transaction. It // takes a keyring signer and the chainID to sign an Ethereum transaction according to // EIP-155 standard. // This method mutates the transaction as it populates the V, R, S // fields of the Transaction's Signature. // The function will fail if the sender address is not defined for the msg or if // the sender is not registered on the keyring func (msg *MsgEthereumTx) Sign(ethSigner ethtypes.Signer, keyringSigner keyring.Signer) error { from := msg.GetFrom() if from.Empty() { return fmt.Errorf("sender address not defined for message") } tx := msg.AsTransaction() txHash := ethSigner.Hash(tx) sig, _, err := keyringSigner.SignByAddress(from, txHash.Bytes()) if err != nil { return err } tx, err = tx.WithSignature(ethSigner, sig) if err != nil { return err } msg.FromEthereumTx(tx) return nil } ``` ### TxData The `MsgEthereumTx` supports the 3 valid Ethereum transaction data types from go-ethereum: `LegacyTx`, `AccessListTx` and `DynamicFeeTx`. These types are defined as protobuf messages and packed into a `proto.Any` interface type in the `MsgEthereumTx` field. * `LegacyTx`: [EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) transaction type * `DynamicFeeTx`: [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) transaction type. Enabled by London hard fork block * `AccessListTx`: [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) transaction type. Enabled by Berlin hard fork block ### `LegacyTx` The transaction data of regular Ethereum transactions. ```go theme={null} type LegacyTx struct { // nonce corresponds to the account nonce (transaction sequence). Nonce uint64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"` // gas price defines the value for each gas unit GasPrice *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=gas_price,json=gasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_price,omitempty"` // gas defines the gas limit defined for the transaction. GasLimit uint64 `protobuf:"varint,3,opt,name=gas,proto3" json:"gas,omitempty"` // hex formatted address of the recipient To string `protobuf:"bytes,4,opt,name=to,proto3" json:"to,omitempty"` // value defines the unsigned integer value of the transaction amount. Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,5,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"` // input defines the data payload bytes of the transaction. Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"` // v defines the signature value V []byte `protobuf:"bytes,7,opt,name=v,proto3" json:"v,omitempty"` // r defines the signature value R []byte `protobuf:"bytes,8,opt,name=r,proto3" json:"r,omitempty"` // s define the signature value S []byte `protobuf:"bytes,9,opt,name=s,proto3" json:"s,omitempty"` } ``` This message field validation is expected to fail if: * `GasPrice` is invalid (`nil` , negative or out of int256 bound) * `Fee` (gasprice \* gaslimit) is invalid * `Amount` is invalid (negative or out of int256 bound) * `To` address is invalid (non valid ethereum hex address) ### `DynamicFeeTx` The transaction data of EIP-1559 dynamic fee transactions. ```go theme={null} type DynamicFeeTx struct { // destination EVM chain ID ChainID *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chainID"` // nonce corresponds to the account nonce (transaction sequence). Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"` // gas tip cap defines the max value for the gas tip GasTipCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=gas_tip_cap,json=gasTipCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_tip_cap,omitempty"` // gas fee cap defines the max value for the gas fee GasFeeCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=gas_fee_cap,json=gasFeeCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_fee_cap,omitempty"` // gas defines the gas limit defined for the transaction. GasLimit uint64 `protobuf:"varint,5,opt,name=gas,proto3" json:"gas,omitempty"` // hex formatted address of the recipient To string `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` // value defines the the transaction amount. Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,7,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"` // input defines the data payload bytes of the transaction. Data []byte `protobuf:"bytes,8,opt,name=data,proto3" json:"data,omitempty"` Accesses AccessList `protobuf:"bytes,9,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"` // v defines the signature value V []byte `protobuf:"bytes,10,opt,name=v,proto3" json:"v,omitempty"` // r defines the signature value R []byte `protobuf:"bytes,11,opt,name=r,proto3" json:"r,omitempty"` // s define the signature value S []byte `protobuf:"bytes,12,opt,name=s,proto3" json:"s,omitempty"` } ``` This message field validation is expected to fail if: * `GasTipCap` is invalid (`nil` , negative or overflows int256) * `GasFeeCap` is invalid (`nil` , negative or overflows int256) * `GasFeeCap` is less than `GasTipCap` * `Fee` (gas price \* gas limit) is invalid (overflows int256) * `Amount` is invalid (negative or overflows int256) * `To` address is invalid (non-valid ethereum hex address) * `ChainID` is `nil` ### `AccessListTx` The transaction data of EIP-2930 access list transactions. ```go theme={null} type AccessListTx struct { // destination EVM chain ID ChainID *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chainID"` // nonce corresponds to the account nonce (transaction sequence). Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"` // gas price defines the value for each gas unit GasPrice *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=gas_price,json=gasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_price,omitempty"` // gas defines the gas limit defined for the transaction. GasLimit uint64 `protobuf:"varint,4,opt,name=gas,proto3" json:"gas,omitempty"` // hex formatted address of the recipient To string `protobuf:"bytes,5,opt,name=to,proto3" json:"to,omitempty"` // value defines the unsigned integer value of the transaction amount. Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,6,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"` // input defines the data payload bytes of the transaction. Data []byte `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"` Accesses AccessList `protobuf:"bytes,8,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"` // v defines the signature value V []byte `protobuf:"bytes,9,opt,name=v,proto3" json:"v,omitempty"` // r defines the signature value R []byte `protobuf:"bytes,10,opt,name=r,proto3" json:"r,omitempty"` // s define the signature value S []byte `protobuf:"bytes,11,opt,name=s,proto3" json:"s,omitempty"` } ``` This message field validation is expected to fail if: * `GasPrice` is invalid (`nil` , negative or overflows int256) * `Fee` (gas price \* gas limit) is invalid (overflows int256) * `Amount` is invalid (negative or overflows int256) * `To` address is invalid (non-valid ethereum hex address) * `ChainID` is `nil` ## ABCI The Application Blockchain Interface (ABCI) allows the application to interact with the Tendermint Consensus engine. The application maintains several ABCI connections with Tendermint. The most relevant for the `x/evm` is the [Consensus connection at Commit](https://docs.tendermint.com/v0.33/app-dev/app-development.html#consensus-connection). This connection is responsible for block execution and calls the functionsΒ `InitChain` (containing `InitGenesis`),Β `BeginBlock`,Β `DeliverTx`,Β `EndBlock`,Β `Commit`Β . `InitChain`Β is only called the first time a new blockchain is started andΒ `DeliverTx`Β is called for each transaction in the block. ### InitGenesis `InitGenesis` initializes the EVM module genesis state by setting the `GenesisState` fields to the store. In particular, it sets the parameters and genesis accounts (state and code). ### ExportGenesis The `ExportGenesis` ABCI function exports the genesis state of the EVM module. In particular, it retrieves all the accounts with their bytecode, balance and storage, the transaction logs, and the EVM parameters and chain configuration. ### BeginBlock The EVM module `BeginBlock` logic is executed prior to handling the state transitions from the transactions. The main objective of this function is to: * Set the context for the current block so that the block header, store, gas meter, etc. are available to the `Keeper` once one of the `StateDB` functions are called during EVM state transitions. * Set the EIP-155 `ChainID` number (obtained from the full chain-id), in case it hasn't been set before during `InitChain` ### EndBlock The EVM module `EndBlock` logic occurs after executing all the state transitions from the transactions. The main objective of this function is to: * Emit Block bloom events * This is due for web3 compatibility as the Ethereum headers contain this type as a field. The JSON-RPC service uses this event query to construct an Ethereum header from a Tendermint header. * The block bloom filter value is obtained from the transient store and then emitted ## Hooks The `x/evm` module implements an `EvmHooks` interface that extend and customize the `Tx` processing logic externally. This supports EVM contracts to call native cosmos modules by 1. defining a log signature and emitting the specific log from the smart contract, 2. recognizing those logs in the native tx processing code, and 3. converting them to native module calls. To do this, the interface includes a `PostTxProcessing` hook that registers custom `Tx` hooks in the `EvmKeeper`. These `Tx` hooks are processed after the EVM state transition is finalized and doesn't fail. Note that there are no default hooks implemented in the EVM module. ```go theme={null} type EvmHooks interface { // Must be called after tx is processed successfully, if return an error, the whole transaction is reverted. PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error } ``` ## `PostTxProcessing` `PostTxProcessing` is only called after an EVM transaction finished successfully and delegates the call to underlying hooks. If no hook has been registered, this function returns with a `nil` error. ```go theme={null} func (k *Keeper) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error { if k.hooks == nil { return nil } return k.hooks.PostTxProcessing(k.Ctx(), msg, receipt) } ``` It's executed in the same cache context as the EVM transaction, if it returns an error, the whole EVM transaction is reverted, if the hook implementor doesn't want to revert the tx, they can always return `nil` instead. The error returned by the hooks is translated to a VM error `failed to process native logs`, the detailed error message is stored in the return value. The message is sent to native modules asynchronously, there's no way for the caller to catch and recover the error. ### Use Case: Call Native ERC20 Module on HyperPaxeer Here is an example taken from the HyperPaxeer [erc20 module](erc20.md) that shows how the `EVMHooks` supports a contract calling a native module to convert ERC-20 Tokens into Cosmos native Coins. Following the steps from above. You can define and emit a `Transfer` log signature in the smart contract like this: ```solidity theme={null} event Transfer(address indexed from, address indexed to, uint256 value); function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } ``` The application will register a `BankSendHook` to the `EvmKeeper`. It recognizes the ethereum tx `Log` and converts it to a call to the bank module's `SendCoinsFromAccountToAccount` method: ```go theme={null} const ERC20EventTransfer = "Transfer" // PostTxProcessing implements EvmHooks.PostTxProcessing func (k Keeper) PostTxProcessing( ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt, ) error { params := h.k.GetParams(ctx) if !params.EnableErc20 || !params.EnableEVMHook { // no error is returned to allow for other post-processing txs // to pass return nil } erc20 := contracts.ERC20BurnableContract.ABI for i, log := range receipt.Logs { if len(log.Topics) < 3 { continue } eventID := log.Topics[0] // event ID event, err := erc20.EventByID(eventID) if err != nil { // invalid event for ERC20 continue } if event.Name != types.ERC20EventTransfer { h.k.Logger(ctx).Info("emitted event", "name", event.Name, "signature", event.Sig) continue } transferEvent, err := erc20.Unpack(event.Name, log.Data) if err != nil { h.k.Logger(ctx).Error("failed to unpack transfer event", "error", err.Error()) continue } if len(transferEvent) == 0 { continue } tokens, ok := transferEvent[0].(*big.Int) // safety check and ignore if amount not positive if !ok || tokens == nil || tokens.Sign() != 1 { continue } // check that the contract is a registered token pair contractAddr := log.Address id := h.k.GetERC20Map(ctx, contractAddr) if len(id) == 0 { // no token is registered for the caller contract continue } pair, found := h.k.GetTokenPair(ctx, id) if !found { continue } // check that conversion for the pair is enabled if !pair.Enabled { // continue to allow transfers for the ERC20 in case the token pair is disabled h.k.Logger(ctx).Debug( "ERC20 token -> Cosmos coin conversion is disabled for pair", "coin", pair.Denom, "contract", pair.Erc20Address, ) continue } // ignore as the burning always transfers to the zero address to := common.BytesToAddress(log.Topics[2].Bytes()) if !bytes.Equal(to.Bytes(), types.ModuleAddress.Bytes()) { continue } // check that the event is Burn from the ERC20Burnable interface // NOTE: assume that if they are burning the token that has been registered as a pair, they want to mint a Cosmos coin // create the corresponding sdk.Coin that is paired with ERC20 coins := sdk.Coins{{Denom: pair.Denom, Amount: sdk.NewIntFromBigInt(tokens)}} // Mint the coin only if ERC20 is external switch pair.ContractOwner { case types.OWNER_MODULE: _, err = h.k.CallEVM(ctx, erc20, types.ModuleAddress, contractAddr, true, "burn", tokens) case types.OWNER_EXTERNAL: err = h.k.bankKeeper.MintCoins(ctx, types.ModuleName, coins) default: err = types.ErrUndefinedOwner } if err != nil { h.k.Logger(ctx).Debug( "failed to process EVM hook for ER20 -> coin conversion", "coin", pair.Denom, "contract", pair.Erc20Address, "error", err.Error(), ) continue } // Only need last 20 bytes from log.topics from := common.BytesToAddress(log.Topics[1].Bytes()) recipient := sdk.AccAddress(from.Bytes()) // transfer the tokens from ModuleAccount to sender address if err := h.k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, coins); err != nil { h.k.Logger(ctx).Debug( "failed to process EVM hook for ER20 -> coin conversion", "tx-hash", receipt.TxHash.Hex(), "log-idx", i, "coin", pair.Denom, "contract", pair.Erc20Address, "error", err.Error(), ) continue } } return nil ``` Lastly, register the hook in `app.go`: ```go theme={null} app.EvmKeeper = app.EvmKeeper.SetHooks(app.Erc20Keeper) ``` ## Events The `x/evm` module emits the Cosmos SDK events after a state execution. The EVM module emits events of the relevant transaction fields, as well as the transaction logs (ethereum events). ### MsgEthereumTx | Type | Attribute Key | Attribute Value | | ------------ | ------------------ | ----------------------- | | ethereum\_tx | `"amount"` | `{amount}` | | ethereum\_tx | `"recipient"` | `{hex_address}` | | ethereum\_tx | `"contract"` | `{hex_address}` | | ethereum\_tx | `"txHash"` | `{tendermint_hex_hash}` | | ethereum\_tx | `"ethereumTxHash"` | `{hex_hash}` | | ethereum\_tx | `"txIndex"` | `{tx_index}` | | ethereum\_tx | `"txGasUsed"` | `{gas_used}` | | tx\_log | `"txLog"` | `{tx_log}` | | message | `"sender"` | `{eth_address}` | | message | `"action"` | `"ethereum"` | | message | `"module"` | `"evm"` | Additionally, the EVM module emits an event during `EndBlock` for the filter query block bloom. ### ABCI | Type | Attribute Key | Attribute Value | | ------------ | ------------- | -------------------- | | block\_bloom | `"bloom"` | `string(bloomBytes)` | ## Parameters The evm module contains the following parameters: ### Params | Key | Type | Default Value | | --------------------- | ------------- | ------------------ | | `EVMDenom` | string | `"ahpx"` | | ~~`EnableCreate`~~ | bool | `true` | | ~~`EnableCall`~~ | bool | `true` | | `ExtraEIPs` | \[]int | TBD | | `ChainConfig` | ChainConfig | See ChainConfig | | `AllowUnprotectedTxs` | bool | false | | `ActivePrecompiles` | \[]string | \[] | | `AccessControl` | AccessControl | Permissionless EVM | ### EVM denom The evm denomination parameter defines the token denomination used on the EVM state transitions and gas consumption for EVM messages. For example, on Ethereum, the `evm_denom` would be `ETH`. In the case of HyperPaxeer, the default denomination is the **atto HyperPaxeer**. In terms of precision, `HyperPaxeer` and `ETH` share the same value, *i.e.* `1 HyperPaxeer = 10^18 atto HyperPaxeer` and `1 ETH = 10^18 wei`. :::tip Note: SDK applications that want to import the EVM module as a dependency will need to set their own `evm_denom` (i.e not `"ahpx"`). ::: ### Enable Create **(deprecated in v19.0.0)** The enable create parameter toggles state transitions that use the `vm.Create` function. When the parameter is disabled, it will prevent all contract creation functionality. ### Enable Transfer **(deprecated in v19.0.0)** The enable transfer toggles state transitions that use the `vm.Call` function. When the parameter is disabled, it will prevent transfers between accounts and executing a smart contract call. ### Extra EIPs The extra EIPs parameter defines the set of activateable Ethereum Improvement Proposals (**[EIPs](https://ethereum.org/en/eips/)**) on the Ethereum VM `Config` that apply custom jump tables. :::tip NOTE: some of these EIPs are already enabled by the chain configuration, depending on the hard fork number. ::: The supported activateable EIPS are: * **[EIP 1344](https://eips.ethereum.org/EIPS/eip-1344)** * **[EIP 1884](https://eips.ethereum.org/EIPS/eip-1884)** * **[EIP 2200](https://eips.ethereum.org/EIPS/eip-2200)** * **[EIP 2315](https://eips.ethereum.org/EIPS/eip-2315)** * **[EIP 2929](https://eips.ethereum.org/EIPS/eip-2929)** * **[EIP 3198](https://eips.ethereum.org/EIPS/eip-3198)** * **[EIP 3529](https://eips.ethereum.org/EIPS/eip-3529)** * **[EIP 3855](https://eips.ethereum.org/EIPS/eip-3855)** ### Chain Config The `ChainConfig` is a protobuf wrapper type that contains the same fields as the go-ethereum `ChainConfig` parameters, but using `*sdk.Int` types instead of `*big.Int`. By default, all block configuration fields but `ConstantinopleBlock`, are enabled at genesis (height 0). #### ChainConfig Defaults | Name | Default Value | | ------------------- | -------------------------------------------------------------------- | | HomesteadBlock | 0 | | DAOForkBlock | 0 | | DAOForkSupport | `true` | | EIP150Block | 0 | | EIP150Hash | `0x0000000000000000000000000000000000000000000000000000000000000000` | | EIP155Block | 0 | | EIP158Block | 0 | | ByzantiumBlock | 0 | | ConstantinopleBlock | 0 | | PetersburgBlock | 0 | | IstanbulBlock | 0 | | MuirGlacierBlock | 0 | | BerlinBlock | 0 | | LondonBlock | 0 | | ArrowGlacierBlock | 0 | | GrayGlacierBlock | 0 | | MergeNetsplitBlock | 0 | | ShanghaiBlock | 0 | | CancunBlock. | 0 | ### Allow Unprotected Transactions This parameter enforces [EIP-155 replay protection](../concepts/replay-protection.md) globally for all nodes partaking in consensus. If disabled, this delegates control of replay protection to the individual nodes (read more [here](../../validate/setup-and-configuration/configuration.md#eip-155-replay-protection)). ### Active Precompiles This parameter governs which [EVM Extensions](../../develop/smart-contracts/evm-extensions/evm-extensions.md) are enabled on the given network. It accepts a list of addresses in Hex format, which is evaluated in EVM transactions to only allow interactions with the selected precompiled contracts. ### Access Control (added in v19.0.0) This parameter enables detailed control of the EVM. The former parameters `enable_create` and `enable_call` have been extended to give exact control of who can access these features. By default, the EVM is *permissionless*, meaning that everyone can deploy smart contracts and send EVM transaction unless they have specifically been blacklisted. The blacklisted addresses can be defined in the corresponding `AccessControlList`. By setting the individual `AccessControlType` for either the create or call functionality as *restricted*, the EVM does not accept further interactions with the specific functionality. When defining the control type as being *permissioned*, the given list of addresses is interpreted as a collection of whitelisted addresses, which are the only ones capable of deploying contracts or calling the EVM respectively. ## Client A user can query and interact with theΒ `evm`Β module using the CLI, JSON-RPC, gRPC or REST. ### CLI Find below a list ofΒ `hyperpaxd`Β commands added with theΒ `x/evm`Β module. You can obtain the full list by using theΒ `hyperpaxd -h`Β command. #### Queries TheΒ `query`Β commands allow users to queryΒ `evm`Β state. **`code`** Allows users to query the smart contract code at a given address. ```bash theme={null} hyperpaxd query evm code ADDRESS [flags] ``` ```bash theme={null} # Example $ hyperpaxd query evm code 0x7bf7b17da59880d9bcca24915679668db75f9397 # Output code: "0xef616c92f3cfc9e92dc270d6acff9cea213cecc7020a76ee4395af09bdceb4837a1ebdb5735e11e7d3adb6104e0c3ac55180b4ddf5e54d022cc5e8837f6a4f971b" ``` **`storage`** Allows users to query storage for an account with a given key and height. ```bash theme={null} hyperpaxd query evm storage ADDRESS KEY [flags] ``` ```bash theme={null} # Example $ hyperpaxd query evm storage 0x0f54f47bf9b8e317b214ccd6a7c3e38b893cd7f0 0 --height 0 # Output value: "0x0000000000000000000000000000000000000000000000000000000000000000" ``` #### Transactions TheΒ `tx`Β commands allow users to interact with theΒ `evm`Β module. **`raw`** Allows users to build cosmos transactions from raw ethereum transaction. ```bash theme={null} hyperpaxd tx evm raw TX_HEX [flags] ``` ```bash theme={null} # Example $ hyperpaxd tx evm raw 0xf9ff74c86aefeb5f6019d77280bbb44fb695b4d45cfe97e6eed7acd62905f4a85034d5c68ed25a2e7a8eeb9baf1b84 # Output value: "0x0000000000000000000000000000000000000000000000000000000000000000" ``` ### JSON-RPC For an overview on the JSON-RPC methods and namespaces supported on HyperPaxeer, please refer to [https://docs.paxeer.app/develop/api/ethereum-json-rpc/methodsl](https://docs.paxeer.app/develop/api/ethereum-json-rpc/methods) ### gRPC #### Queries | Verb | Method | Description | | ------ | ------------------------------------------------------ | ---------------------------------------------------------------------------- | | `gRPC` | `hyperpaxeer.evm.v1.Query/Account` | Get an Ethereum account | | `gRPC` | `hyperpaxeer.evm.v1.Query/CosmosAccount` | Get an Ethereum account's Cosmos Address | | `gRPC` | `hyperpaxeer.evm.v1.Query/ValidatorAccount` | Get an Ethereum account's from a validator consensus Address | | `gRPC` | `hyperpaxeer.evm.v1.Query/Balance` | Get the balance of a the EVM denomination for a single EthAccount. | | `gRPC` | `hyperpaxeer.evm.v1.Query/Storage` | Get the balance of all coins for a single account | | `gRPC` | `hyperpaxeer.evm.v1.Query/Code` | Get the balance of all coins for a single account | | `gRPC` | `hyperpaxeer.evm.v1.Query/Params` | Get the parameters of x/evm module | | `gRPC` | `hyperpaxeer.evm.v1.Query/EthCall` | Implements the eth\_call rpc api | | `gRPC` | `hyperpaxeer.evm.v1.Query/EstimateGas` | Implements the eth\_estimateGas rpc api | | `gRPC` | `hyperpaxeer.evm.v1.Query/TraceTx` | Implements the debug\_traceTransaction rpc api | | `gRPC` | `hyperpaxeer.evm.v1.Query/TraceBlock` | Implements the debug\_traceBlockByNumber and debug\_traceBlockByHash rpc api | | `GET` | `/hyperpaxeer/evm/v1/account/{address}` | Get an Ethereum account | | `GET` | `/hyperpaxeer/evm/v1/cosmos_account/{address}` | Get an Ethereum account's Cosmos Address | | `GET` | `/hyperpaxeer/evm/v1/validator_account/{cons_address}` | Get an Ethereum account's from a validator consensus Address | | `GET` | `/hyperpaxeer/evm/v1/balances/{address}` | Get the balance of a the EVM denomination for a single EthAccount. | | `GET` | `/hyperpaxeer/evm/v1/storage/{address}/{key}` | Get the balance of all coins for a single account | | `GET` | `/hyperpaxeer/evm/v1/codes/{address}` | Get the balance of all coins for a single account | | `GET` | `/hyperpaxeer/evm/v1/params` | Get the parameters of x/evm module | | `GET` | `/hyperpaxeer/evm/v1/eth_call` | Implements the eth\_call rpc api | | `GET` | `/hyperpaxeer/evm/v1/estimate_gas` | Implements the eth\_estimateGas rpc api | | `GET` | `/hyperpaxeer/evm/v1/trace_tx` | Implements the debug\_traceTransaction rpc api | | `GET` | `/hyperpaxeer/evm/v1/trace_block` | Implements the debug\_traceBlockByNumber and debug\_traceBlockByHash rpc api | #### Transactions | Verb | Method | Description | | ------ | ----------------------------------- | ------------------------------- | | `gRPC` | `hyperpaxeer.evm.v1.Msg/EthereumTx` | Submit an Ethereum transactions | | `POST` | `/hyperpaxeer/evm/v1/ethereum_tx` | Submit an Ethereum transactions | # Feemarket Source: https://sidiorresearchlabs.mintlify.app/protocol/modules/feemarket # `feemarket` ## Abstract This document specifies the feemarket module, which allows defining a global transaction fee for the network. This module has been designed to support EIP-1559 in cosmos-sdk. The `MempoolFeeDecorator` in `x/auth` module needs to be overwritten to check the `baseFee` along with the `minimal-gas-prices` allowing to implement a global fee mechanism which vary depending on the network activity. For more reference to EIP-1559: [EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) ## Contents 1. **[Concepts](#concepts)** 2. **[State](#state)** 3. **[Begin Block](#begin-block)** 4. **[End Block](#end-block)** 5. **[Keeper](#keeper)** 6. **[Events](#events)** 7. **[Params](#params)** 8. **[Client](#client)** 9. **[AnteHandlers](#antehandlers)** ## Concepts ### EIP-1559: Fee Market [EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) describes a pricing mechanism that was proposed on Ethereum to improve to calculation of transaction fees. It includes a fixed-per-block network fee that is burned and dynamically expands/contracts block sizes to deal with peaks of network congestion. Before EIP-1559 the transaction fee is calculated with ``` fee = gasPrice * gasLimit ``` where `gasPrice` is the price per gas and `gasLimit` describes the amount of gas required to perform the transaction. The more complex operations a transaction requires, the higher the gas limit (see [Executing EVM bytecode](evm.md#executing-evm-bytecode)). To submit a transaction, the signer needs to specify the `gasPrice`. With EIP-1559 enabled, the transaction fee is calculated with ``` fee = (baseFee + priorityTip) * gasLimit ``` where `baseFee` is the fixed-per-block network fee per gas and `priorityTip` is an additional fee per gas that can be set optionally. Note, that both the base fee and the priority tip are gas prices. To submit a transaction with EIP-1559, the signer needs to specify the `gasFeeCap`, which is the maximum fee per gas they are willing to pay in total. Optionally, the `priorityTip` can be specified, which covers both the priority fee and the block's network fee per gas (aka: base fee). :::tip The Cosmos SDK uses a different terminology for `gas` than Ethereum. What is called `gasLimit` on Ethereum is called `gasWanted` on Cosmos. You might encounter both terminologies on HyperPaxeer since it builds Ethereum on top of the SDK, e.g. when using different wallets like Keplr for Cosmos and Metamask for Ethereum. ::: ### Base Fee The base fee per gas (aka base fee) is a global gas price defined at the consensus level. It is stored as a module parameter and is adjusted at the end of each block based on the total gas used in the previous block and gas target (`block gas limit / elasticity multiplier`): * it increases when blocks are above the gas target, * it decreases when blocks are below the gas target. Instead of burning the base fee (as implemented on Ethereum), the `feemarket` module allocates the base fee for regular [Cosmos SDK fee distribution](https://docs.cosmos.network/main/modules/distribution). ### Priority Tip In EIP-1559, the `max_priority_fee_per_gas`, often referred to as `tip`, is an additional gas price that can be added to the `baseFee` in order to incentivize transaction prioritization. The higher the tip, the more likely the transaction is included in the block. Until the Cosmos SDK version v0.46, however, there is no notion of transaction prioritization. Thus, the tip for an EIP-1559 transaction on HyperPaxeer should be zero (`MaxPriorityFeePerGas` JSON-RPC endpoint returns `0`). Have a look at the [mempool](https://docs.paxeer.app/validate/setup-and-configuration/mempool) docs to read more about how to leverage transaction prioritization. ### Effective Gas price For EIP-1559 transactions (dynamic fee transactions) the effective gas price describes the maximum gas price that a transaction is willing to provide. It is derived from the transaction arguments and the base fee parameter. Depending on which one is smaller, the effective gas price is either the `baseFee + tip` or the `gasFeeCap` ``` min(baseFee + gasTipCap, gasFeeCap) ``` ### Local vs. Global Minimum Gas Prices Minimum gas prices are used to discard spam transactions in the network, by raising the cost of transactions to the point that it is not economically viable for the spammer. This is achieved by defining a minimum gas price for accepting txs in the mempool for both Cosmos and EVM transactions. A transaction is discarded from the mempool if it doesn't provide at least one of the two types of min gas prices: Minimum gas prices are used to discard spam transactions in the network, by raising the cost of transactions to the point that it is not economically viable for the spammer. This is achieved by defining a minimum gas price for accepting txs in the mempool for both Cosmos and EVM transactions. A transaction is discarded from the mempool if it doesn't provide at least one of the two types of min gas prices: 1. the local min gas prices that validators can set on their node config and 2. the global min gas price, which is set as a parameter in the `feemarket` module, which can be changed through governance. The lower bound for a transaction gas price is determined by comparing of gas price bounds according to three cases: 1. If the effective gas price (`effective gas price = base fee + priority tip`) or the local minimum gas price is lower than the global `MinGasPrice` (`min-gas-price (local) < MinGasPrice (global) OR EffectiveGasPrice < MinGasPrice`), then `MinGasPrice` is used as a lower bound. 2. If transactions are rejected due to having a gas price lower than `MinGasPrice`, users need to resend the transactions with a gas price higher or equal to `MinGasPrice`. 3. If the effective gas price or the local `minimum-gas-price` is higher than the global `MinGasPrice`, then the larger value of the two is used as a lower bound. In the case of EIP-1559, users must increase the priority fee for their transactions to be valid. The comparison of transaction gas price and the lower bound is implemented through AnteHandler decorators. For EVM transactions, this is done in the `EthMempoolFeeDecorator` and `EthMinGasPriceDecorator` `AnteHandler` and for Cosmos transactions in `NewMempoolFeeDecorator` and `MinGasPriceDecorator` `AnteHandler`. :::tip If the base fee decreases to a value below the global `MinGasPrice`, it is set to the `MinGasPrice`. This is implemented, so that the base fee can't drop to gas prices that wouldn't allow transactions to be accepted in the mempool, because of a higher `MinGasPrice`. ::: ## State The x/feemarket module keeps in the state variable needed to the fee calculation: Only BlockGasUsed in previous block needs to be tracked in state for the next base fee calculation. | | Description | Key | Value | Store | | ------------ | --------------------- | ----------- | ------------------ | ----- | | BlockGasUsed | gas used in the block | `[]byte{1}` | `[]byte{gas_used}` | KV | ## Begin block The base fee is calculated at the beginning of each block. ### Base Fee #### Disabling base fee We introduce two parameters : `NoBaseFee`and `EnableHeight` `NoBaseFee` controls the feemarket base fee value. If set to true, no calculation is done and the base fee returned by the keeper is zero. `EnableHeight` controls the height we start the calculation. * If `NoBaseFee = false` and `height < EnableHeight`, the base fee value will be equal to `base_fee` defined in the genesis and the `BeginBlock` will return without further computation. * If `NoBaseFee = false` and `height >= EnableHeight`, the base fee is dynamically calculated upon each block at `BeginBlock`. Those parameters allow us to introduce a static base fee or activate the base fee at a later stage. #### Enabling base fee To enable EIP-1559 with the EVM, the following parameters should be set : * NoBaseFee should be false * EnableHeight should be set to a positive integer >= upgrade height. It defines at which height the chain starts the base fee adjustment * LondonBlock evm's param should be set to a positive integer >= upgrade height. It defines at which height the chain starts to accept EIP-1559 transactions. #### Calculation The base fee is initialized at `EnableHeight` to the `InitialBaseFee` value defined in the genesis file. The base fee is after adjusted according to the total gas used in the previous block. ```go theme={null} parent_gas_target = parent_gas_limit / ELASTICITY_MULTIPLIER if EnableHeight == block.number base_fee = INITIAL_BASE_FEE else if parent_gas_used == parent_gas_target: base_fee = parent_base_fee else if parent_gas_used > parent_gas_target: gas_used_delta = parent_gas_used - parent_gas_target base_fee_delta = max(parent_base_fee * gas_used_delta / parent_gas_target / BASE_FEE_MAX_CHANGE_DENOMINATOR, 1) base_fee = parent_base_fee + base_fee_delta else: gas_used_delta = parent_gas_target - parent_gas_used base_fee_delta = parent_base_fee * gas_used_delta / parent_gas_target / BASE_FEE_MAX_CHANGE_DENOMINATOR base_fee = parent_base_fee - base_fee_delta ``` ## End block The `block_gas_used` value is updated at the end of each block. ### Block Gas Used The total gas used by current block is stored in the KVStore at `EndBlock`. It is initialized to `block_gas` defined in the genesis. ## Keeper The feemarket module provides this exported keeper that can be passed to other modules, which require access to the base fee value ```go theme={null} type Keeper interface { GetBaseFee(ctx sdk.Context) *big.Int } ``` ## Events The `x/feemarket` module emits the following events: ### BeginBlocker | Type | Attribute Key | Attribute Value | | ----------- | ------------- | ----------------- | | fee\_market | base\_fee | `{baseGasPrices}` | ### EndBlocker | Type | Attribute Key | Attribute Value | | ---------- | ------------- | ---------------- | | block\_gas | height | `{blockHeight}` | | block\_gas | amount | `{blockGasUsed}` | ## Parameters The `x/feemarket` module contains the following parameters: | Key | Type | Default Values | Description | | ------------------------ | ------- | -------------- | ----------------------------------------------------------------------------------------------------------------------- | | NoBaseFee | bool | false | control the base fee adjustment | | BaseFeeChangeDenominator | uint32 | 8 | bounds the amount the base fee that can change between blocks | | ElasticityMultiplier | uint32 | 2 | bounds the threshold which the base fee will increase or decrease depending on the total gas used in the previous block | | BaseFee | uint32 | 1000000000 | base fee for EIP-1559 blocks | | EnableHeight | uint32 | 0 | height which enable fee adjustment | | MinGasPrice | sdk.Dec | 0 | global minimum gas price that needs to be paid to include a transaction in a block | ## Client ### CLI A user can query and interact with theΒ `feemarket`Β module using the CLI. #### Queries TheΒ `query`Β commands allow users to queryΒ `feemarket`Β state. ```bash theme={null} hyperpaxd query feemarket --help ``` ##### Base Fee The `base-fee` command allows users to query the block base fee by height. ```bash theme={null} hyperpaxd query feemarket base-fee [flags] ``` Example: ```bash theme={null} hyperpaxd query feemarket base-fee ... ``` Example Output: ``` base_fee: "512908936" ``` ##### Block Gas The `block-gas` command allows users to query the block gas by height. ```bash theme={null} hyperpaxd query feemarket block-gas [flags] ``` Example: ```bash theme={null} hyperpaxd query feemarket block-gas ... ``` Example Output: ``` gas: "21000" ``` ##### Params The `params` command allows users to query the module params. ```bash theme={null} hyperpaxd query params subspace [subspace] [key] [flags] ``` Example: ```bash theme={null} hyperpaxd query params subspace feemarket ElasticityMultiplier ... ``` Example Output: ``` key: ElasticityMultiplier subspace: feemarket value: "2" ``` ### gRPC #### Queries | Verb | Method | Description | | ------ | ----------------------------------------- | ---------------------- | | `gRPC` | `hyperpaxeer.feemarket.v1.Query/Params` | Get the module params | | `gRPC` | `hyperpaxeer.feemarket.v1.Query/BaseFee` | Get the block base fee | | `gRPC` | `hyperpaxeer.feemarket.v1.Query/BlockGas` | Get the block gas used | | `GET` | `/hyperpaxeer/feemarket/v1/params` | Get the module params | | `GET` | `/hyperpaxeer/feemarket/v1/base_fee` | Get the block base fee | | `GET` | `/hyperpaxeer/feemarket/v1/block_gas` | Get the block gas used | ## AnteHandlers The `x/feemarket` module provides `AnteDecorator`s that are recursively chained together into a single [`Antehandler`](https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-alpha1/docs/architecture/adr-010-modular-antehandler.md). These decorators perform basic validity checks on an Ethereum or Cosmos SDK transaction, such that it could be thrown out of the transaction Mempool. Note that the `AnteHandler` is run for every transaction and called on both `CheckTx` and `DeliverTx`. ### Decorators ### `MinGasPriceDecorator` Rejects Cosmos SDK transactions with transaction fees lower than `MinGasPrice * GasLimit`. ### `EthMinGasPriceDecorator` Rejects EVM transactions with transactions fees lower than `MinGasPrice * GasLimit`. * For `LegacyTx` and `AccessListTx`, the `GasPrice * GasLimit` is used. * For EIP-1559 (*aka.* `DynamicFeeTx`), the `EffectivePrice * GasLimit` is used. :::tip **Note**: For dynamic transactions, if the `feemarket` formula results in a `BaseFee` that lowers `EffectivePrice < MinGasPrices`, the users must increase the `GasTipCap` (priority fee) until `EffectivePrice > MinGasPrices`. Transactions with `MinGasPrices * GasLimit < transaction fee < EffectiveFee` are rejected by the `feemarket` `AnteHandle`. ::: ### `EthGasConsumeDecorator` Calculates the effective fees to deduct and the tx priority according to EIP-1559 spec, then deducts the fees and sets the tx priority in the response. ``` effectivePrice = min(baseFee + tipFeeCap, gasFeeCap) effectiveTipFee = effectivePrice - baseFee priority = effectiveTipFee / DefaultPriorityReduction ``` When there are multiple messages in the transaction, choose the lowest priority in them. # Modules Source: https://sidiorresearchlabs.mintlify.app/protocol/modules/index Cosmos SDK modules and how they compose the protocol. # List of Modules Here is a list of all production-grade modules that can be used on the HyperPaxeer blockchain, along with their respective documentation: * [epochs](epochs.md) - Executes custom state transitions every period (*aka* epoch). * [erc20](erc20.md) - Trustless, on-chain bidirectional internal conversion of tokens between HyperPaxeer' EVM and Cosmos runtimes. * [evm](evm.md) - Smart Contract deployment and execution on Cosmos * [feemarket](feemarket.md) - Fee market implementation based on the EIP-1559 specification. * [inflation](inflation.md) - Mint tokens and allocate them to staking rewards and the community pool. * [paxoracle](paxoracle.md) - Validator-submitted price feeds exposed to EVM contracts through the `0x903` OracleAggregator precompile. * [vesting](vesting.md) - Vesting accounts with lockup and clawback capabilities. ## Cosmos SDK HyperPaxeer uses the following Cosmos SDK modules: * [auth](https://docs.cosmos.network/main/modules/auth) - Authentication of accounts and transactions for Cosmos SDK applications. * [authz](https://docs.cosmos.network/main/modules/authz) - Authorization for accounts to perform actions on behalf of other accounts. * [bank](https://docs.cosmos.network/main/modules/bank) - Token transfer functionalities. * [capability](https://ibc.cosmos.network/main/ibc/capability-module) - Object capability implementation. * [distribution](https://docs.cosmos.network/main/modules/distribution) - Fee distribution, and staking token provision distribution. * [evidence](https://docs.cosmos.network/main/modules/evidence) - Evidence handling for double signing, misbehaviour, etc. * [feegrant](https://docs.cosmos.network/main/modules/feegrant) - Grant fee allowances for executing transactions. * [genutil](https://github.com/cosmos/cosmos-sdk/tree/main/x/genutil) - variety of genesis utility functionalities for usage within a blockchain application * [gov](https://docs.cosmos.network/main/modules/gov) - On-chain proposals and voting. * [params](https://docs.cosmos.network/main/modules/params) - Globally available parameter store. * [slashing](https://docs.cosmos.network/main/modules/slashing) - Validator punishment mechanisms. * [staking](https://docs.cosmos.network/main/modules/staking) - Proof-of-Stake layer for public blockchains. * [upgrade](https://docs.cosmos.network/main/modules/upgrade) - Software upgrades handling and coordination. ## IBC HyperPaxeer uses the following the IBC modules for the SDK: * [interchain-accounts](https://ibc.cosmos.network/main/apps/interchain-accounts/overview.html) * [transfer](https://ibc.cosmos.network/main/apps/transfer/overview.html) # Inflation Source: https://sidiorresearchlabs.mintlify.app/protocol/modules/inflation # `inflation` ## Abstract The `x/inflation` module mints new HyperPaxeer tokens and allocates them in daily epochs according to the [HyperPaxeer Token Model](https://Paxeer-Network.blog/the-HyperPaxeer-token-model-edc07014978b) distribution to * Community Pool `50%`. * Staking Rewards `50%`, * Usage Incentives: `0%`, It replaces the Cosmos SDK `x/mint` module, that other Cosmos chains are using. The allocation of new coins incentivizes specific behaviour in the HyperPaxeer network. Inflation allocates funds to 1) the community pool(managed by sdk `x/distribution` module) to fund spending proposals, and 2) the `Fee Collector account` (in the sdk `x/auth` module) to increase staking rewards. The now deprecated `x/incentives` module account (3) does not accrue tokens anymore. ## Contents 1. **[Concepts](#concepts)** 2. **[State](#state)** 3. **[Hooks](#hooks)** 4. **[Events](#events)** 5. **[Parameters](#parameters)** 6. **[Clients](#clients)** ## Concepts ### Inflation In a Proof of Stake (PoS) blockchain, inflation is used as a tool to incentivize participation in the network. Inflation creates and distributes new tokens to participants who can use their tokens to either interact with the protocol or stake their assets to earn rewards and vote for governance proposals. Especially in an early stage of a network, where staking rewards are high and there are fewer possibilities to interact with the network, inflation can be used as the major tool to incentivize staking and thereby securing the network. With more stakers, the network becomes increasingly stable and decentralized. It becomes *stable*, because assets are locked up instead of causing price changes through trading. And it becomes *decentralized,* because the power to vote for governance proposals is distributed amongst more people. ### HyperPaxeer Token Model The HyperPaxeer Token Model outlines how the HyperPaxeer network is secured through a balanced incentivized interest from users, developers and validators. In this model, inflation plays a major role in sustaining this balance. With an initial supply of 200 million and over 300 million tokens being issued through inflation during the first year, the model suggests an exponential decline in inflation to issue 1 billion HyperPaxeer tokens within the first 4 years. We implement two different inflation mechanisms to support the token model: 1. linear inflation for team vesting and 2. exponential inflation for staking rewards and community pool. #### Linear Inflation - Team Vesting The Team Vesting distribution in the Token Model is implemented in a way that minimized the amount of taxable events. An initial supply of 200M allocated to `vesting accounts` at genesis. This amount is equal to the total inflation allocated for team vesting after 4 years (`20% * 1B = 200M`). Over time, `unvested` tokens on these accounts are converted into `vested` tokens at a linear rate. Team members cannot delegate, transfer or execute Ethereum transaction with `unvested` tokens until they are unlocked represented as `vested` tokens. #### Exponential Inflation - **The Half Life** The inflation distribution for staking and community pool is implemented through an exponential formula, a.k.a. the Half Life. Inflation is minted in daily epochs. During a period of 365 epochs (one year), a daily provision (`epochProvison`) of HyperPaxeer tokens is minted and allocated to staking rewards and the community pool. The epoch provision depends on module parameters and is recalculated at the end of every epoch. The calculation of the epoch provision is done according to the following formula: ```latex theme={null} periodProvision = exponentialDecay * bondingIncentive f(x) = (a * (1 - r) ^ x + c) * (1 + maxVariance * (1 - bondedRatio / bondingTarget)) epochProvision = periodProvision / epochsPerPeriod where (with default values): x = variable = year a = 300,000,000 = initial value r = 0.5 = decay factor c = 9,375,000 = long term supply bondedRatio = variable = fraction of the staking tokens which are currently bonded maxVariance = 0.0 = the max amount to increase inflation bondingTarget = 0.66 = our optimal bonded ratio ``` ```latex theme={null} Example with bondedRatio = bondingTarget: period periodProvision cumulated epochProvision f(0) 309 375 000 309 375 000 847 602 f(1) 159 375 000 468 750 000 436 643 f(2) 84 375 000 553 125 000 231 164 f(3) 46 875 000 600 000 000 128 424 ``` Note, that after [discussion](https://www.mintscan.io/Paxeer-Network/proposals/258) with the validator community, it was decided to decrease the inflation to 1/3 during the upgrade to [v16.0.0](https://www.mintscan.io/Paxeer-Network/proposals/265). ## State ### State Objects The `x/inflation` module keeps the following objects in state: | State Object | Description | Key | Value | Store | | --------------- | ------------------------------ | ----------- | ------------------------- | ----- | | Period | Period Counter | `[]byte{1}` | `[]byte{period}` | KV | | EpochIdentifier | Epoch identifier bytes | `[]byte{3}` | `[]byte{epochIdentifier}` | KV | | EpochsPerPeriod | Epochs per period bytes | `[]byte{4}` | `[]byte{epochsPerPeriod}` | KV | | SkippedEpochs | Number of skipped epochs bytes | `[]byte{5}` | `[]byte{skippedEpochs}` | KV | #### Period Counter to keep track of amount of past periods, based on the epochs per period. #### EpochIdentifier Identifier to trigger epoch hooks. #### EpochsPerPeriod Amount of epochs in one period ### Genesis State The `x/inflation` module's `GenesisState` defines the state necessary for initializing the chain from a previously exported height. It contains the module parameters, the current period, epoch identifier, epochs per period and the number of skipped epochs. : ```go theme={null} type GenesisState struct { // params defines all the parameters of the module. Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` // amount of past periods, based on the epochs per period param Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` // inflation epoch identifier EpochIdentifier string `protobuf:"bytes,3,opt,name=epoch_identifier,json=epochIdentifier,proto3" json:"epoch_identifier,omitempty"` // number of epochs after which inflation is recalculated EpochsPerPeriod int64 `protobuf:"varint,4,opt,name=epochs_per_period,json=epochsPerPeriod,proto3" json:"epochs_per_period,omitempty"` // number of epochs that have passed while inflation is disabled SkippedEpochs uint64 `protobuf:"varint,5,opt,name=skipped_epochs,json=skippedEpochs,proto3" json:"skipped_epochs,omitempty"` } ``` ## Hooks The `x/inflation` module implements the `AfterEpochEnd` hook from the `x/epoch` module in order to allocate inflation. ### Epoch Hook: Inflation The epoch hook handles the inflation logic which is run at the end of each epoch. It is responsible for minting and allocating the epoch mint provision as well as updating it: 1. Check if inflation is disabled. If it is, skip inflation, increment number of skipped epochs and return without proceeding to the next steps. 2. A block is committed, that signalizes that an `epoch` has ended (block `header.Time` has surpassed `epoch_start` + `epochIdentifier`). 3. Mint coin in amount of calculated `epochMintProvision` and allocate according to inflation distribution to staking rewards and community pool. 4. If a period ends with the current epoch, increment the period by `1` and set new value to the store. ## Events The `x/inflation` module emits the following events: ### Inflation | Type | Attribute Key | Attribute Value | | ----------- | -------------------- | --------------------------------------------- | | `inflation` | `"epoch_provisions"` | `{fmt.Sprintf("%d", epochNumber)}` | | `inflation` | `"epoch_number"` | `{strconv.FormatUint(uint64(in.Epochs), 10)}` | | `inflation` | `"amount"` | `{mintedCoin.Amount.String()}` | ## Parameters The `x/inflation` module contains the parameters described below. All parameters can be modified via governance. | Key | Type | Default Value | | ------------------------------------- | ---------------------- | --------------------------------------------------- | | `ParamStoreKeyMintDenom` | string | `evm.DefaultEVMDenom` // β€œahpx” | | `ParamStoreKeyExponentialCalculation` | ExponentialCalculation | `A: sdk.NewDec(int64(300_000_000))` | | | | `R: sdk.NewDecWithPrec(50, 2)` | | | | `C: sdk.NewDec(int64(9_375_000))` | | | | `BondingTarget: sdk.NewDecWithPrec(66, 2)` | | | | `MaxVariance: sdk.ZeroDec()` | | `ParamStoreKeyInflationDistribution` | InflationDistribution | `StakingRewards: sdk.NewDecWithPrec(500000000, 9)` | | | | `UsageIncentives: sdk.NewDecWithPrec(000000000, 9)` | | | | `CommunityPool: sdk.NewDecWithPrec(500000000, 9)` | | `ParamStoreKeyEnableInflation` | bool | `true` | ### Mint Denom The `ParamStoreKeyMintDenom` parameter sets the denomination in which new coins are minted. ### Exponential Calculation The `ParamStoreKeyExponentialCalculation` parameter holds all values required for the calculation of the `epochMintProvision`. The values `A`, `R` and `C` describe the decrease of inflation over time. The `BondingTarget` and `MaxVariance` allow for an increase in inflation, which is automatically regulated by the `bonded ratio`, the portion of staked tokens in the network. The exact formula can be found under [Concepts](#concepts). ### Inflation Distribution The `ParamStoreKeyInflationDistribution` parameter defines the distribution in which inflation is allocated through minting on each epoch (`stakingRewards`, `CommunityPool`). ### Enable Inflation The `ParamStoreKeyEnableInflation` parameter enables the daily inflation. If it is disabled, no tokens are minted and the number of skipped epochs increases for each passed epoch. ## Clients A user can query the `x/inflation` module using the CLI, JSON-RPC, gRPC or REST. ### CLI Find below a list ofΒ `hyperpaxd`Β commands added with theΒ `x/inflation`Β module. You can obtain the full list by using theΒ `hyperpaxd -h`Β command. #### Queries TheΒ `query`Β commands allow users to queryΒ `inflation`Β state. **`period`** Allows users to query the current inflation period. ```bash theme={null} hyperpaxd query inflation period [flags] ``` **`epoch-mint-provision`** Allows users to query the current inflation epoch provisions value. ```bash theme={null} hyperpaxd query inflation epoch-mint-provision [flags] ``` **`skipped-epochs`** Allows users to query the current number of skipped epochs. ```bash theme={null} hyperpaxd query inflation skipped-epochs [flags] ``` **`total-supply`** Allows users to query the total supply of tokens in circulation. ```bash theme={null} hyperpaxd query inflation total-supply [flags] ``` **`inflation-rate`** Allows users to query the inflation rate of the current period. ```bash theme={null} hyperpaxd query inflation inflation-rate [flags] ``` **`params`** Allows users to query the current inflation parameters. ```bash theme={null} hyperpaxd query inflation params [flags] ``` #### Proposals **Update Params** Allows users to submit a `MsgUpdateParams` with the desired changes on the `x/inflation` module parameters. To do this, you will have to provide a JSON file with the correspondiong message in the `submit-proposal` command. For more information on how to draft a proposal, refer to the [Drafting a proposal section](../Paxeer-Network-cli/proposal-draft.md). ```bash theme={null} hyperpaxd tx gov submit-proposal proposal.json [flags] ``` ### gRPC #### Queries | Verb | Method | Description | | ------ | --------------------------------------------------- | --------------------------------------------- | | `gRPC` | `HyperPaxeer.inflation.v1.Query/Period` | Gets current inflation period | | `gRPC` | `HyperPaxeer.inflation.v1.Query/EpochMintProvision` | Gets current inflation epoch provisions value | | `gRPC` | `HyperPaxeer.inflation.v1.Query/Params` | Gets current inflation parameters | | `gRPC` | `HyperPaxeer.inflation.v1.Query/SkippedEpochs` | Gets current number of skipped epochs | | `gRPC` | `HyperPaxeer.inflation.v1.Query/TotalSupply` | Gets current total supply | | `gRPC` | `HyperPaxeer.inflation.v1.Query/InflationRate` | Gets current inflation rate | | `GET` | `/Paxeer-Network/inflation/v1/period` | Gets current inflation period | | `GET` | `/Paxeer-Network/inflation/v1/epoch_mint_provision` | Gets current inflation epoch provisions value | | `GET` | `/Paxeer-Network/inflation/v1/skipped_epochs` | Gets current number of skipped epochs | | `GET` | `/Paxeer-Network/inflation/v1/total_supply` | Gets current total supply | | `GET` | `/Paxeer-Network/inflation/v1/inflation_rate` | Gets current inflation rate | | `GET` | `/Paxeer-Network/inflation/v1/params` | Gets current inflation parameters | # x/paxoracle Source: https://sidiorresearchlabs.mintlify.app/protocol/modules/paxoracle Validator oracle module backing the OracleAggregator precompile ## Overview `x/paxoracle` stores validator-submitted market prices and exposes aggregated prices to EVM contracts through the OracleAggregator precompile at `0x0000000000000000000000000000000000000903`. The module supports PaxSpot, HyperPax Perps, and other protocols that need validator-consensus price data with sub-second chain finality. ## EVM precompile ```solidity theme={null} interface IOracleAggregator { function getValidatorPrice(bytes32 marketId) external view returns (int256 price, uint256 quorum, uint256 timestamp); function submitPrice(bytes32 marketId, int256 price, uint256 confidence) external returns (bool success); } ``` | Field | Meaning | | ------------ | -------------------------------------------------------------- | | `marketId` | `bytes32` market identifier, commonly `keccak256("BTC/USD")` | | `price` | signed 18-decimal fixed-point price | | `confidence` | validator confidence value, typically `0 < confidence <= 1e18` | | `quorum` | number of validator attestations included in the aggregate | | `timestamp` | block timestamp or block-derived timestamp for the aggregate | ## Read a validator price ```solidity theme={null} IOracleAggregator constant VOM = IOracleAggregator(0x0000000000000000000000000000000000000903); function getBtcUsd() external view returns (int256 price, uint256 quorum) { (price, quorum,) = VOM.getValidatorPrice(keccak256("BTC/USD")); } ``` ## Submit a validator price Only active validators can submit prices. Non-validator addresses should use `getValidatorPrice()` for reads and should not attempt to post attestations. ```solidity theme={null} IOracleAggregator constant VOM = IOracleAggregator(0x0000000000000000000000000000000000000903); function submitBtcUsd(int256 price) external returns (bool) { return VOM.submitPrice({ marketId: keccak256("BTC/USD"), price: price, confidence: 1e18 }); } ``` ```typescript submit-price.ts theme={null} import { createWalletClient, http, keccak256, parseUnits, stringToBytes } from 'viem' import { privateKeyToAccount } from 'viem/accounts' import { hyperpaxeer } from './chains' const account = privateKeyToAccount(process.env.VALIDATOR_EVM_PRIVATE_KEY as `0x${string}`) const wallet = createWalletClient({ account, chain: hyperpaxeer, transport: http('https://public-rpc.paxeer.app/rpc'), }) await wallet.writeContract({ address: '0x0000000000000000000000000000000000000903', abi: [{ type: 'function', name: 'submitPrice', stateMutability: 'nonpayable', inputs: [ { name: 'marketId', type: 'bytes32' }, { name: 'price', type: 'int256' }, { name: 'confidence', type: 'uint256' }, ], outputs: [{ name: 'success', type: 'bool' }], }], functionName: 'submitPrice', args: [ keccak256(stringToBytes('BTC/USD')), parseUnits('97250', 18), parseUnits('1', 18), ], }) ``` ## Aggregation model `x/paxoracle` verifies submissions against the active validator set, filters stale submissions, and returns a confidence-weighted median for each market. | Step | Description | | ---------------- | ------------------------------------------------------------------ | | Validator check | The submitter must be an active validator | | Market lookup | The `marketId` maps to an enabled market | | Staleness filter | Old attestations are excluded from the aggregate | | Quorum check | The aggregate must include enough valid submissions | | Median | Valid submissions are aggregated into a confidence-weighted median | ## Common failure modes | Failure | Cause | | ------------------ | ------------------------------------------------------------- | | Submit reverts | Caller is not an active validator | | No price returned | Market has no valid recent submissions | | Quorum too low | Too few validators submitted within the freshness window | | Invalid confidence | Confidence is zero or outside the accepted range | | Stale aggregate | Submissions are older than the configured staleness threshold | ## Related docs * [PaxSpot precompiles](/paxspot/precompiles) * [EVM extensions](/develop/smart-contracts/list-evm-extensions) * [Current network facts](/current-network) # Vesting Source: https://sidiorresearchlabs.mintlify.app/protocol/modules/vesting # `vesting` ## Abstract This document specifies the internalΒ `x/vesting` module of the HyperPaxeer Hub. The `x/vesting` module introduces the `ClawbackVestingAccount`, a new vesting account type that implements the Cosmos SDK [`VestingAccount`](https://docs.cosmos.network/main/modules/auth/vesting#vesting-account-types) interface. This account is used to allocate tokens that are subject to vesting, lockup, and clawback. The `ClawbackVestingAccount` allows any two parties to agree on a future rewarding schedule, where tokens are granted permissions over time. The parties can use this account to enforce legal contracts or commit to mutual long-term interests. In this commitment, vesting is the mechanism for gradually earning permission to transfer and delegate allocated tokens. Additionally, the lockup provides a mechanism to prevent the right to transfer allocated tokens and perform Ethereum transactions from the account. Both vesting and lockup are defined in schedules at account creation. At any time, the funder of a `ClawbackVestingAccount` can perform a clawback to retrieve unvested tokens. The circumstances under which a clawback should be performed can be agreed upon in a contract (e.g. smart contract). For HyperPaxeer, the `ClawbackVestingAccount` is used to allocate tokens to core team members and advisors to incentivize long-term participation in the project. ## Contents 1. **[Concepts](#concepts)** 2. **[State](#state-transitions)** 3. **[State Transitions](#state-transitions)** 4. **[Transactions](#transactions)** 5. **[AnteHandlers](#antehandlers)** 6. **[Events](#events)** 7. **[Clients](#clients)** ## References * SDK vesting specification: [https://docs.cosmos.network/main/modules/auth/vesting](https://docs.cosmos.network/main/modules/auth/vesting) * SDK vesting implementation: [https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/vesting](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/vesting) * Agoric’s Vesting Clawback Account: [https://github.com/Agoric/agoric-sdk/issues/4085](https://github.com/Agoric/agoric-sdk/issues/4085) * Agoric’s `vestcalc` tool: [https://github.com/agoric-labs/cosmos-sdk/tree/Agoric/x/auth/vesting/cmd/vestcalc](https://github.com/agoric-labs/cosmos-sdk/tree/Agoric/x/auth/vesting/cmd/vestcalc) ## Concepts ### Vesting Vesting describes the process of converting `unvested` into `vested` tokens without transferring the ownership of those tokens. In an unvested state, tokens cannot be transferred to other accounts, delegated to validators, or used for governance. A vesting schedule describes the amount and time at which tokens are vested. The duration until which the first tokens are vested is called the `cliff`. ### Lockup The lockup describes the schedule by which tokens are converted from a `locked` to an `unlocked` state. As long as all tokens are locked, the account cannot perform any transaction that spend HyperPaxeer. However, the account can perform transactions that don't spend HyperPaxeer tokens. Additionally, locked tokens cannot be transferred to other accounts. In the case in which tokens are both locked and vested at the same time, it is possible to delegate them to validators, but not transfer them to other accounts. The following table summarizes the actions that are allowed for tokens that are subject to the combination of vesting and lockup: | Token Status | Transfer | Delegate | Vote | Eth Txs that spend HyperPaxeer\*\* | Eth Txs that don't spend HyperPaxeer (amount = 0)\*\* | | ----------------------- | :------: | :------: | :--: | :--------------------------------: | :---------------------------------------------------: | | `locked` & `unvested` | ❌ | ❌ | ❌ | ❌ | βœ… | | `locked` & `vested` | ❌ | βœ… | βœ… | ❌ | βœ… | | `unlocked` & `unvested` | ❌ | ❌ | ❌ | ❌ | βœ… | | `unlocked` & `vested`\* | βœ… | βœ… | βœ… | βœ… | βœ… | \*Staking rewards are unlocked and vested \*\*EVM transactions only fail if they involve sending locked or unvested HyperPaxeer tokens, e.g. send HyperPaxeer to EOA or Smart Contract (fails if amount > 0 ). ### Schedules Vesting and lockup schedules specify the amount and time at which tokens are vested or unlocked. They are defined as [`periods`](https://docs.cosmos.network/main/modules/auth/vesting#period) where each period has its own length and amount. A typical vesting schedule for instance would be defined starting with a one-year period to represent the vesting cliff, followed by several monthly vesting periods until the total allocated vesting amount is vested. Vesting or lockup schedules can be easily created with Agoric’s [`vestcalc`](https://github.com/agoric-labs/cosmos-sdk/tree/Agoric/x/auth/vesting/cmd/vestcalc) tool. E.g. to calculate a four-year vesting schedule with a one year cliff, starting in January 2022, you can run vestcalc with: ```bash theme={null} vestcalc --write --start=2022-01-01 --coins=200000000000000000000000ahpx --months=48 --cliffs=2023-01-01 ``` ### Clawback In case a `ClawbackVestingAccount`'s underlying commitment or contract is breached, the clawback provides a mechanism to return unvested funds. The account authorized to perform the clawback is defined during `ClawbackVestingAccount` account creation. It can be: * The governance module if allowed * The address specified as the `FunderAddress` It should be noted that the information if an account has governance clawback enabled or not is not stored with the account itself but it is stored directly in the vesting module. When a clawback is initiated, or by the funder or the governance, unvested tokens are send to the destination address specified in the clawback message. If no destination address is specified, the default is to return tokens to the funder. ## State ### State Objects The `x/vesting` module does not keep objects in its own store. Instead, it uses the SDK `auth` module to store account objects in state using the [Account Interface](https://docs.cosmos.network/main/modules/auth#account-interface). Accounts are exposed externally as an interface and stored internally as a clawback vesting account. ### ClawbackVestingAccount An instance that implements the [Vesting Account](https://docs.cosmos.network/main/modules/auth/vesting#vesting-account-types) interface. It provides an account that can hold contributions subject to lockup, or vesting which is subject to clawback of unvested tokens, or a combination (tokens vest, but are still locked). ```go theme={null} type ClawbackVestingAccount struct { // base_vesting_account implements the VestingAccount interface. It contains // all the necessary fields needed for any vesting account implementation *types.BaseVestingAccount `protobuf:"bytes,1,opt,name=base_vesting_account,json=baseVestingAccount,proto3,embedded=base_vesting_account" json:"base_vesting_account,omitempty"` // funder_address specifies the account which can perform clawback FunderAddress string `protobuf:"bytes,2,opt,name=funder_address,json=funderAddress,proto3" json:"funder_address,omitempty"` // start_time defines the time at which the vesting period begins StartTime time.Time `protobuf:"bytes,3,opt,name=start_time,json=startTime,proto3,stdtime" json:"start_time"` // lockup_periods defines the unlocking schedule relative to the start_time LockupPeriods []types.Period `protobuf:"bytes,4,rep,name=lockup_periods,json=lockupPeriods,proto3" json:"lockup_periods"` // vesting_periods defines the vesting schedule relative to the start_time VestingPeriods []types.Period `protobuf:"bytes,5,rep,name=vesting_periods,json=vestingPeriods,proto3" json:"vesting_periods"` } ``` #### BaseVestingAccount Implements the `VestingAccount` interface. It contains all the necessary fields needed for any vesting account implementation. #### FunderAddress Specifies the account which provides the original tokens and can perform clawback. #### StartTime Defines the time at which the vesting and lockup schedules begin. #### LockupPeriods Defines the unlocking schedule relative to the start time. #### VestingPeriods Defines the vesting schedule relative to the start time. ### Genesis State The `x/vesting` module allows the definition of `ClawbackVestingAccounts` at genesis. In this case, the account balance must be logged in the SDK `bank` module balances or automatically adjusted through the `add-genesis-account` CLI command. ## State Transitions The `x/vesting` module allows for state transitions that create and update a clawback vesting account with `CreateClawbackVestingAccount` or perform a clawback of unvested funds with `Clawback`. ### Create Clawback Vesting Account An externally owned account can be converted to a clawback vesting account by the owner. Upon creation, the owner assigns a funder, who is able to fund the account with vesting and/or lockup schedules. The account has also the possibility to specify if the vested tokens can be clawbacked from the governance. 1. Owner submits a `MsgCreateClawbackVestingAccount` through one of the clients. 2. Check if 1. the vesting account address is not blocked. 2. the account at the vesting account address is not already a vesting account. 3. Create a clawback vesting account at the target address with empty vesting and lockup schedules. ### Fund Clawback Vesting Account The funder of a clawback vesting account can fund it with vesting and/or lockup schedules. If a vesting account already has funds, the schedules are merged together. 1. Funder submits a `MsgFundVestingAccount` through one of the clients. 2. Check if 1. the vesting address is not a blocked address. 2. the vesting address is a clawback vesting account. 3. there is at least one vesting or lockup schedule provided. If one of them is absent, default to instant vesting or unlock schedule. 3. lockup and vesting total amounts are equal. 4. Update the clawback vesting account and send coins from the funder to the vesting account, merging any existing schedules with the new funding. ### Clawback The funding address is the only address that can perform the clawback. 1. Funder submits a `MsgClawback` through one of the clients. 2. Check if 1. a destination address is given and default to funder address if not 2. the destination address is not blocked 3. the account exists and is a clawback vesting account 4. account funder is same as in msg 3. Transfer unvested tokens from the clawback vesting account to the destination address, update the lockup schedule and remove future vesting events. ### Update Clawback Vesting Account Funder The funding address of an existing clawback vesting account can be updated only by the current funder. 1. Funder submits a `MsgUpdateVestingFunder` through one of the clients. 2. Check if 1. the new funder address is not blocked 2. the vesting account exists and is a clawback vesting account 3. account funder is same as in msg 3. Update the vesting account funder with the new funder address. ### Convert Vesting Account Once all tokens are vested, the vesting account can be converted back to an `EthAccount`. 1. Owner of vesting account submits a `MsgConvertVestingAccount` through one of the clients. 2. Check if 1. the vesting account exists and is a clawback vesting account 2. the vesting account's vesting and locked schedules have concluded 3. Convert the vesting account to an `EthAccount` ## Transactions This section defines the concrete `sdk.Msg` types, that result in the state transitions defined on the previous section. ### `CreateClawbackVestingAccount` ```go theme={null} type MsgCreateClawbackVestingAccount struct { // funder_address specifies the account that will be able to fund the vesting account FunderAddress string `protobuf:"bytes,1,opt,name=funder_address,json=funderAddress,proto3" json:"funder_address,omitempty"` // vesting_address specifies the address that will receive the vesting tokens VestingAddress string `protobuf:"bytes,2,opt,name=vesting_address,json=vestingAddress,proto3" json:"vesting_address,omitempty"` // enable_gov_clawback specifies whether the governance module can clawback this account EnableGovClawback bool `protobuf:"varint,3,opt,name=enable_gov_clawback,json=enableGovClawback,proto3" json:"enable_gov_clawback,omitempty"` } ``` The msg content stateless validation fails if: * `FunderAddress` or `VestingAddress` are invalid ### `FundVestingAccount` ```go theme={null} type MsgFundVestingAccount struct { // funder_address specifies the account that funds the vesting account FunderAddress string `protobuf:"bytes,1,opt,name=funder_address,json=funderAddress,proto3" json:"funder_address,omitempty"` // vesting_address specifies the account that receives the funds VestingAddress string `protobuf:"bytes,2,opt,name=vesting_address,json=vestingAddress,proto3" json:"vesting_address,omitempty"` // start_time defines the time at which the vesting period begins StartTime time.Time `protobuf:"bytes,3,opt,name=start_time,json=startTime,proto3,stdtime" json:"start_time"` // lockup_periods defines the unlocking schedule relative to the start_time LockupPeriods github_com_cosmos_cosmos_sdk_x_auth_vesting_types.Periods `protobuf:"bytes,4,rep,name=lockup_periods,json=lockupPeriods,proto3,castrepeated=github.com/cosmos/cosmos-sdk/x/auth/vesting/types.Periods" json:"lockup_periods"` // vesting_periods defines the vesting schedule relative to the start_time VestingPeriods github_com_cosmos_cosmos_sdk_x_auth_vesting_types.Periods `protobuf:"bytes,5,rep,name=vesting_periods,json=vestingPeriods,proto3,castrepeated=github.com/cosmos/cosmos-sdk/x/auth/vesting/types.Periods" json:"vesting_periods"` } ``` The msg content stateless validation fails if: * `FunderAddress` or `VestingAddress` are invalid * `LockupPeriods` and `VestingPeriods` * include a period with a non-positive length or amount * do not describe the same total amount ### `Clawback` ```go theme={null} type MsgClawback struct { // funder_address is the address which funded the account FunderAddress string `protobuf:"bytes,1,opt,name=funder_address,json=funderAddress,proto3" json:"funder_address,omitempty"` // account_address is the address of the ClawbackVestingAccount to claw back from. AccountAddress string `protobuf:"bytes,2,opt,name=account_address,json=accountAddress,proto3" json:"account_address,omitempty"` // dest_address specifies where the clawed-back tokens should be transferred // to. If empty, the tokens will be transferred back to the original funder of // the account. DestAddress string `protobuf:"bytes,3,opt,name=dest_address,json=destAddress,proto3" json:"dest_address,omitempty"` } ``` The msg content stateless validation fails if: * `FunderAddress` or `AccountAddress` are invalid * `DestAddress` is not empty and invalid ### `UpdateVestingFunder` ```go theme={null} type MsgUpdateVestingFunder struct { // funder_address is the current funder address of the ClawbackVestingAccount FunderAddress string `protobuf:"bytes,1,opt,name=funder_address,json=funderAddress,proto3" json:"funder_address,omitempty"` // new_funder_address is the new address to replace the existing funder_address NewFunderAddress string `protobuf:"bytes,2,opt,name=new_funder_address,json=newFunderAddress,proto3" json:"new_funder_address,omitempty"` // vesting_address is the address of the ClawbackVestingAccount being updated VestingAddress string `protobuf:"bytes,3,opt,name=vesting_address,json=vestingAddress,proto3" json:"vesting_address,omitempty"` } ``` The msg content stateless validation fails if: * `FunderAddress`, `NewFunderAddress` or `VestingAddress` are invalid ### `ConvertVestingAccount` ```go theme={null} type MsgConvertVestingAccount struct { // vesting_address is the address of the ClawbackVestingAccount being updated VestingAddress string `protobuf:"bytes,2,opt,name=vesting_address,json=vestingAddress,proto3" json:"vesting_address,omitempty"` } ``` The msg content stateless validation fails if: * `VestingAddress` is invalid ## AnteHandlers The `x/vesting` module provides `AnteDecorator`s that are recursively chained together into a single [`Antehandler`](https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-alpha1/docs/architecture/adr-010-modular-antehandler.md). These decorators perform basic validity checks on an Ethereum, such that it could be thrown out of the transaction Mempool. Note that theΒ `AnteHandler`Β is called on bothΒ `CheckTx`Β andΒ `DeliverTx`, as CometBFT proposers presently have the ability to include in their proposed block transactions that failΒ `CheckTx`. ### Decorators The following decorators implement the vesting logic for token delegation and performing EVM transactions. #### `EthVestingTransactionDecorator` Validates if a clawback vesting account is permitted to perform Ethereum transactions, based on if it has its vesting schedule has surpassed the vesting cliff and first lockup period. Also, validates if the account has sufficient unlocked tokens to execute the transaction. This AnteHandler decorator will fail if: * the message is not a `MsgEthereumTx` * sender account cannot be found * sender account is not a `ClawbackVestingAccount` * block time is before surpassing vesting cliff end (with zero vested coins) AND * block time is before surpassing all lockup periods (with non-zero locked coins) * sender account has insufficient unlocked tokens to execute the transaction ### Custom Staking Module Evomos introduced the concept of [EVM extensions](https://docs.paxeer.app/develop/smart-contracts/evm-extensions) to allow smart contract to interact with Cosmos SDK modules like staking and distribution, to provide a better developer experience allowing users to interact with Cosmos native module via the EVM. Since a `ClawbackVestingAccount` is allowed to stake only unlocked & vested coins, or locked & vested, we have to ensure that all other configurations are not permitted to perform a state transition. Instead of having these checks implemented in both the `AnteHandler`s for Cosmos transactions and Ethereum transactions, HyperPaxeer core wraps the Cosmos SDK `x/staking` module to introduce these checks in the `MsgServer` of this module. With this approach we ensure that all staking actions, through direct Cosmos message or through extensions, are validating the account balance in the proper way. The staking wrapper uses the same functionalities of the original staking module but introduces required checks in the following methods: * `Delegate` * `CreateValidator` ## Events The `x/vesting` module emits the following events: ### Create Clawback Vesting Account | Type | Attibute Key | Attibute Value | | --------------------------------- | ------------ | ---------------------- | | `create_clawback_vesting_account` | `"funder"` | `{msg.FunderAddress}` | | `create_clawback_vesting_account` | `"sender"` | `{msg.VestingAddress}` | ### Fund Vesting Account | Type | Attibute Key | Attibute Value | | ---------------------- | -------------- | -------------------------- | | `fund_vesting_account` | `"funder"` | `{msg.FunderAddress}` | | `fund_vesting_account` | `"coins"` | `{vestingCoins.String()}` | | `fund_vesting_account` | `"start_time"` | `{msg.StartTime.String()}` | | `fund_vesting_account` | `"account"` | `{msg.VestingAddress}` | ### Clawback | Type | Attibute Key | Attibute Value | | ---------- | --------------- | ---------------------- | | `clawback` | `"funder"` | `{msg.FromAddress}` | | `clawback` | `"account"` | `{msg.AccountAddress}` | | `clawback` | `"destination"` | `{msg.DestAddress}` | ### Update Clawback Vesting Account Funder | Type | Attibute Key | Attibute Value | | ----------------------- | -------------- | ------------------------ | | `update_vesting_funder` | `"funder"` | `{msg.FromAddress}` | | `update_vesting_funder` | `"account"` | `{msg.VestingAddress}` | | `update_vesting_funder` | `"new_funder"` | `{msg.NewFunderAddress}` | ## Clients A user can query the HyperPaxeer `x/vesting`Β module using the CLI, gRPC, or REST. ### CLI Find below a list ofΒ `hyperpaxd`Β commands added with the `x/vesting`Β module. You can obtain the full list by using theΒ `hyperpaxd -h`Β command. #### Genesis TheΒ genesis configuration commands allow users to configure the genesisΒ `vesting` accountΒ state. `add-genesis-account` Allows users to set up clawback vesting accounts at genesis, funded with an allocation of tokens, subject to clawback. Must provide a lockup periods file (`--lockup`), a vesting periods file (`--vesting`), or both. If both files are given, they must describe schedules for the same total amount. If one file is omitted, it will default to a schedule that immediately unlocks or vests the entire amount. The described amount of coins will be transferred from the --from address to the vesting account. Unvested coins may be "clawed back" by the funder with the clawback command. Coins may not be transferred out of the account if they are locked or unvested. Only vested coins may be staked. For an example of how to set this see [this link](https://github.com/Paxeer-Network/Paxeer-Network/pull/303). ```go theme={null} hyperpaxd add-genesis-account ADDRESS_OR_KEY_NAME COIN... [flags] ``` #### Queries TheΒ `query`Β commands allow users to queryΒ `vesting` accountΒ state. **`balances`** Allows users to query the locked, unvested and vested tokens for a given vesting account ```go theme={null} hyperpaxd query vesting balances ADDRESS [flags] ``` #### Transactions TheΒ `tx`Β commands allow users to create and clawbackΒ `vesting` accountΒ state. **`create-clawback-vesting-account`** A new clawback vesting account is created for the sender account (`--from`), if it is not already of such type. Only the designated funder will be able to define lockup and vesting schedules and has to do so using the fund-vesting-account subcommand. Clawback via governance is enabled or disabled through the second argument. ```go theme={null} hyperpaxd tx vesting create-clawback-vesting-account FUNDER_ADDRESS ENABLE_GOV_CLAWBACK --from=VESTING_ADDRESS [flags] ``` **`fund-vesting-account`** Allows the funder account to update a clawback vesting account with new schedules. Any existing schedules are merged with the newly added schedules. Must provide a lockup periods file (--lockup), a vesting periods file (--vesting), or both. If both files are given, they must describe schedules for the same total amount. If one file is omitted, it will default to a schedule that immediately unlocks or vests the entire amount. The described amount of coins will be transferred from the --from address to the vesting account. Unvested coins may be "clawed back" by the funder with the clawback command. Coins may not be transferred out of the account if they are locked or unvested. Only vested coins may be staked. For an example of how to set this see [this link](https://github.com/Paxeer-Network/Paxeer-Network/pull/303). ```go theme={null} hyperpaxd tx vesting fund-vesting-account VESTING_ADDRESS --from=FUNDER_ADDRESS [flags] ``` **`clawback`** Allows to transfer all unvested unvested tokens out of a ClawbackVestingAccount. Must be requested by the original funder address (--from) and may provide a destination address (--dest), otherwise the coins are returned to the funder. Delegated or unbonding staking tokens will be transferred in the delegated or unbonding state. The recipient is vulnerable to slashing, and must act to unbond the tokens if desired. ```go theme={null} hyperpaxd tx vesting clawback VESTING_ADDRESS --from=FUNDER_ADDRESS [flags] ``` **`update-vesting-funder`** Allows users to update the funder of an existent `ClawbackVestingAccount`. Must be requested by the original funder address (`--from`). ```go theme={null} hyperpaxd tx vesting update-vesting-funder VESTING_ADDRESS NEW_FUNDER_ADDRESS --from=FUNDER_ADDRESS [flags] ``` **`convert`** Allows users to convert their vesting account to the chain's default account (i.e `EthAccount`). This operation only succeeds if there are no unvested tokens left in the account. ```go theme={null} hyperpaxd tx vesting convert VESTING_ADDRESS [flags] ``` ### gRPC #### Queries | Verb | Method | Description | | ------ | ----------------------------------------------- | -------------------------------------- | | `gRPC` | `HyperPaxeer.vesting.v2.Query/Balances` | Gets locked, unvested and vested coins | | `GET` | `/Paxeer-Network/vesting/v2/balances/{address}` | Gets locked, unvested and vested coins | #### Transactions | Verb | Method | Description | | ------ | --------------------------------------------------------------- | ----------------------------------------------- | | `gRPC` | `HyperPaxeer.vesting.v2.Msg/CreateClawbackVestingAccount` | Creates clawback vesting account | | `gRPC` | `HyperPaxeer.vesting.v2.Msg/FundVestingAccount` | Funds a clawback vesting account | | `gRPC` | `/Paxeer-Network.vesting.v2.Msg/Clawback` | Performs clawback | | `gRPC` | `/Paxeer-Network.vesting.v2.Msg/UpdateVestingFunder` | Updates vesting account funder | | `gRPC` | `/Paxeer-Network.vesting.v2.Msg/ConvertVestingAccount` | Converts vesting account back to normal account | | `GET` | `/Paxeer-Network/vesting/v2/tx/create_clawback_vesting_account` | Creates clawback vesting account | | `GET` | `/Paxeer-Network/vesting/v2/tx/fund_vesting_account` | Funds a clawback vesting account | | `GET` | `/Paxeer-Network/vesting/v2/tx/clawback` | Performs clawback | | `GET` | `/Paxeer-Network/vesting/v2/tx/update_vesting_funder` | Updates vesting account funder | | `GET` | `/Paxeer-Network/vesting/v2/tx/convert_vesting_account` | Converts vesting account back to normal account | # Quick Start Source: https://sidiorresearchlabs.mintlify.app/quickstart Connect a wallet, run a node, and deploy your first contract on HyperPaxeer in under ten minutes ## 1. Connect a Wallet HyperPaxeer is a standard EVM chain (Chain ID `125`). Any Ethereum-compatible wallet works β€” MetaMask, Rabby, or the native **PaxPort Wallet**. PaxPort ships with HyperPaxeer pre-configured β€” no manual network setup required. Download from [paxportwallet.com](http://paxportwallet.com) . Open your wallet's network settings and add: | Field | Value | | --------------- | ----------------------------------- | | Network Name | `HyperPaxeer` | | RPC URL | `https://public-rpc.paxeer.app/rpc` | | Chain ID | `125` | | Currency Symbol | `HPX` | | Block Explorer | `https://paxscan.io` | *** ## 2. Run a Node (Optional) The `hpx` CLI deploys Docker-based RPC or Validator nodes with a single command. Minimum requirements: 16 GB RAM, 6 CPU cores, 300 GB disk, Ubuntu 22.04+. ```bash theme={null} curl -sSL https://hyperpaxeer.com/hyper-os/new/get-hpx.sh | sudo bash ``` The installer checks your system, installs dependencies, and launches an interactive setup wizard. After setup: ```bash theme={null} hpx deploy my-rpc rpc # deploy an RPC node hpx deploy my-val validator # deploy a validator node hpx dashboard # live status of all nodes ``` Each node gets its own Docker Compose stack under `/root/hyperpax-nodes//` with isolated ports that auto-increment. | Command | Purpose | | -------------------------------- | ------------------------------- | | `hpx list` | List all registered nodes | | `hpx info ` | Sync status, height, peers | | `hpx logs ` | Stream node logs | | `hpx start all` / `hpx stop all` | Bulk lifecycle | | `hpx capacity` | Show remaining server resources | See [Run a Validator](/validate/setup/run-a-validator) for the full operator guide. *** ## 3. Deploy a Smart Contract HyperPaxeer is fully compatible with Solidity tooling. Foundry is the recommended framework. ```bash theme={null} # Install Foundry curl -L https://foundry.paradigm.xyz | bash && foundryup # Create project forge init my-project && cd my-project # Deploy (use --legacy --slow for Alexandria Fork chains) forge create src/Counter.sol:Counter \ --rpc-url https://public-rpc.paxeer.app/rpc \ --private-key $PRIVATE_KEY \ --legacy --slow ``` ```bash theme={null} npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox ``` ```javascript hardhat.config.js theme={null} module.exports = { solidity: "0.8.24", networks: { hyperpaxeer: { url: "https://public-rpc.paxeer.app/rpc", chainId: 125, accounts: [process.env.PRIVATE_KEY] } } }; ``` ```bash theme={null} npx hardhat run scripts/deploy.js --network hyperpaxeer ``` 1. Open [remix.ethereum.org](https://remix.ethereum.org) 2. Write or import your contract 3. Compile with Solidity 0.8.24+ 4. Connect MetaMask (ensure Chain ID 125 is selected) 5. Deploy via **Injected Provider β€” MetaMask** Store private keys in a `.env` file and never commit them to version control. *** ## 4. Verify on PaxScan ```bash theme={null} forge verify-contract \ --chain-id 125 \ --compiler-version v0.8.24 \ DEPLOYED_ADDRESS \ src/Counter.sol:Counter \ --verifier blockscout \ --verifier-url https://paxscan.io/api ``` *** ## 5. Integrate in a Frontend ```typescript wagmi-config.ts theme={null} import { createConfig, http } from 'wagmi' import { defineChain } from 'viem' export const hyperpaxeer = defineChain({ id: 125, name: 'HyperPaxeer', network: 'hyperpaxeer', nativeCurrency: { decimals: 18, name: 'HyperPaxeer', symbol: 'HPX' }, rpcUrls: { default: { http: ['https://public-rpc.paxeer.app/rpc'] }, }, blockExplorers: { default: { name: 'PaxScan', url: 'https://paxscan.io' }, }, }) export const config = createConfig({ chains: [hyperpaxeer], transports: { [hyperpaxeer.id]: http() }, }) ``` *** ## Next Steps wagmi, viem, ethers.js, and web3.js setup Deployment patterns, verification, and interaction guides Dual-VM design, precompiles, and the x/paxoracle module Test RPC methods against the live network # RPC Methods Source: https://sidiorresearchlabs.mintlify.app/rpc Test HyperPaxeer RPC methods in real-time ## Overview Test HyperPaxeer RPC methods in real-time. Select an example or write your own JSON-RPC request. **RPC Endpoint:** `https://public-rpc.paxeer.app/rpc` **125** **HPX** ## Common RPC Methods ### eth\_blockNumber Returns the number of the most recent block. ```json Request theme={null} { "jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1 } ``` ```json Response theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x5daf3b" } ``` None `QUANTITY` - Integer of the current block number the client is on *** ### eth\_getBalance Returns the balance of the account of given address. ```json Request theme={null} { "jsonrpc": "2.0", "method": "eth_getBalance", "params": [ "0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest" ], "id": 1 } ``` ```json Response theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x0234c8a3397aab58" } ``` 1. `DATA`, 20 Bytes - Address to check for balance 2. `QUANTITY|TAG` - Integer block number, or the string "latest", "earliest" or "pending" `QUANTITY` - Integer of the current balance in wei *** ### eth\_gasPrice Returns the current price per gas in wei. ```json Request theme={null} { "jsonrpc": "2.0", "method": "eth_gasPrice", "params": [], "id": 1 } ``` ```json Response theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x09184e72a000" } ``` None `QUANTITY` - Integer of the current gas price in wei *** ### eth\_chainId Returns the chain ID of the current network. ```json Request theme={null} { "jsonrpc": "2.0", "method": "eth_chainId", "params": [], "id": 1 } ``` ```json Response theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0xe5" } ``` None `QUANTITY` - Integer of the current chain ID (125 for HyperPaxeer) *** ### eth\_call Executes a new message call immediately without creating a transaction on the blockchain. ```json Request theme={null} { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "data": "0x..." }, "latest" ], "id": 1 } ``` ```json Response theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0x..." } ``` 1. `Object` - The transaction call object * `from`: (optional) Address - The address the transaction is sent from * `to`: Address - The address the transaction is directed to * `gas`: (optional) Integer - Gas provided for the transaction execution * `gasPrice`: (optional) Integer - Gas price provided for each paid gas * `value`: (optional) Integer - Value sent with this transaction * `data`: (optional) Data - Hash of the method signature and encoded parameters 2. `QUANTITY|TAG` - Integer block number, or the string "latest", "earliest" or "pending" `DATA` - The return value of the executed contract *** ### eth\_sendTransaction Creates new message call transaction or a contract creation. This method requires a wallet connection to sign the transaction. ```json Request theme={null} { "jsonrpc": "2.0", "method": "eth_sendTransaction", "params": [ { "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "gas": "0x76c0", "gasPrice": "0x9184e72a000", "value": "0x9184e72a", "data": "0x..." } ], "id": 1 } ``` ```json Response theme={null} { "jsonrpc": "2.0", "id": 1, "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" } ``` 1. `Object` - The transaction object * `from`: Address - The address the transaction is sent from * `to`: (optional) Address - The address the transaction is directed to (null for contract creation) * `gas`: (optional) Integer - Gas provided for the transaction execution * `gasPrice`: (optional) Integer - Gas price provided for each paid gas * `value`: (optional) Integer - Value sent with this transaction * `data`: Data - Compiled contract code or hash of the invoked method signature and encoded parameters `DATA`, 32 Bytes - The transaction hash, or the zero hash if the transaction is not yet available *** ### eth\_getTransactionByHash Returns information about a transaction by transaction hash. ```json Request theme={null} { "jsonrpc": "2.0", "method": "eth_getTransactionByHash", "params": [ "0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b" ], "id": 1 } ``` ```json Response theme={null} { "jsonrpc": "2.0", "id": 1, "result": { "blockHash": "0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2", "blockNumber": "0x5daf3b", "from": "0xa7d9ddbe1f17865597fbd27ec712455208b6b76d", "gas": "0xc350", "gasPrice": "0x4a817c800", "hash": "0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b", "input": "0x68656c6c6f21", "nonce": "0x15", "to": "0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb", "transactionIndex": "0x41", "value": "0xf3dbb76162000", "v": "0x25", "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c" } } ``` 1. `DATA`, 32 Bytes - Hash of a transaction `Object` - A transaction object, or null when no transaction was found ## Using with cURL ```bash theme={null} curl -X POST \ https://public-rpc.paxeer.app/rpc \ -H 'Content-Type: application/json' \ -d '{ "jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1 }' ``` ## Using with JavaScript ```javascript theme={null} const response = await fetch('https://public-rpc.paxeer.app/rpc', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1, }), }); const data = await response.json(); console.log(data.result); ``` ## Using with Python ```python theme={null} import requests import json url = 'https://public-rpc.paxeer.app/rpc' payload = { 'jsonrpc': '2.0', 'method': 'eth_blockNumber', 'params': [], 'id': 1 } response = requests.post(url, json=payload) print(response.json()) ``` ## Next Steps Complete API documentation for all methods Integration examples and code samples # Sidiora.ag Source: https://sidiorresearchlabs.mintlify.app/sidiora/ag Network-operated meta-aggregator routing layer for Paxeer liquidity, adapters, quotes, vault settlement, and transaction tracking ## Overview Sidiora.ag is the public protocol name for the Paxeer Eqos Central Order Router (PECOR) meta-aggregator. It routes across network-operated liquidity systems and tracks quote, execution, and settlement state. Route through adapters for Sidiora.fun, oracle feeds, vaults, and order systems. Transaction tracking records order lifecycle and route execution state. Quoter contracts provide route previews before execution. ## Architecture | Component | Role | | -------------------- | ------------------------------------------- | | `PECORRouter` | Main routing entry point | | `OracleHub` | Shared oracle hub for routing and valuation | | `PriceOracleAdapter` | Price oracle adapter | | `SidioraFeedAdapter` | Sidiora feed adapter | | `VaultAdapter` | Vault integration adapter | | `SidioraAdapter` | Sidiora liquidity adapter | | `TransactionTracker` | Execution and lifecycle tracking | | `PECORVault` | Vault settlement component | | `PECOROrders` | Order management layer | | `PECORQuoter` | Quote simulation layer | ## Current production addresses | Contract | Address | | ------------------ | -------------------------------------------- | | OracleHub | `0xED7620DC28759d55D89fF802E307Dd246d61D409` | | PriceOracleAdapter | `0x02D04a000E09c47d6BCFc1D6afb43Cac5d62d1c9` | | SidioraFeedAdapter | `0x2531dFa65CB370771ca695cf9620140022ab360B` | | VaultAdapter | `0x8C362D903ad5ce3E42b2E7a00686aE5E3aF0B0F6` | | SidioraAdapter | `0x5882D31D5E5E22395863DAe0fe977B2C978C9f33` | | PECORRouter | `0x5925FA311707C406D83FC76317a69bb1Ba263F32` | ## Legacy PECOR v3 addresses | Contract | Address | | ------------------ | -------------------------------------------- | | PriceOracle | `0x921A37182339b1618CB55937448c66B6538BF225` | | TransactionTracker | `0xf656612D8F305E4867d8203176f5656bB69be958` | | PECORVault | `0x6500B1B3F8067772041C68b2c51D8E7A84e20C31` | | PECOR | `0xae894b953ec1dD9b305346dEc1484Fe0ffF5eaD4` | | PECOROrders | `0x39DCa28a022fED90Bc7964E84330b3871D02692D` | | PECORQuoter | `0x4e643931fbb2df1B5965739B46CF70BCe622BD0a` | ## Connected Sidiora.fun addresses | Contract | Address | | ------------ | -------------------------------------------- | | PoolRegistry | `0x1F22f11325197fae71937598F6935cc4e9231970` | | Quoter | `0xeDb3B45E320A8ab2306Fa1C303742f2478fd3E0a` | | Router | `0xB2D63300FE8b3508A83728e8f36B98e845eBD980` | ## Token addresses | Token | Address | | ----- | -------------------------------------------- | | USDC | `0xf8850b62AE017c55be7f571BBad840b4f3DA7D49` | | USDT | `0x5dfE06Ae465a39c442c45ed273c523BaC2d1f6a8` | | USDL | `0x7c69c84daAEe90B21eeCABDb8f0387897E9B7B37` | | USID | `0x6C32c255EeBD6A72B56ee82454d7140020919652` | | WPAX9 | `0xe5ccf339d1c89c7e6c6768b28507f78b861fc1de` | | SID | `0x86949e4CdB89496490890B67C9cfF63eD8efB4b1` | ## Developer usage Start with the active router address for route execution: ```typescript theme={null} const sidioraAgRouter = '0x5925FA311707C406D83FC76317a69bb1Ba263F32' ``` Use Sidiora.fun Quoter for launchpad pool quotes and PECOR routing components for aggregate route planning. ## Related protocols * [Sidiora.fun](/sidiora/fun) * [HyperPax DEX](/sidiora/dex) * [HyperPax Perps](/sidiora/perps) # HyperPax DEX Source: https://sidiorresearchlabs.mintlify.app/sidiora/dex Network-operated Adaptive Sigmoid AMM with Diamond facets, progressive fees, oracle-pegged pools, and typed SDK support ## Overview HyperPax DEX is the public protocol name for the network-operated v5-ASAMM system. It is an Adaptive Sigmoid Automated Market Maker built for Paxeer Network chain ID `125`. A tanh-based curve keeps small trades efficient and increases impact for large trades. Fees scale quadratically with trade size to protect pool liquidity. 12 EIP-2535 facets share one AppStorage layout behind a single Diamond. ## Core mechanics ### Sigmoid price impact ```text theme={null} P(x) = P_mid * (1 + k * tanh(a * x / L)) ``` | Parameter | Meaning | | --------- | ----------------------------------------- | | `P_mid` | Current mid-price from reserves or oracle | | `k` | Maximum price deviation factor | | `a` | Curve steepness | | `x` | Signed trade size | | `L` | Pool liquidity | ### Progressive fee ```text theme={null} fee(x) = baseFee + impactFee * (x / L)^2 ``` Fees are distributed as: | Recipient | Share | | ------------------ | ----: | | LPs | `70%` | | Protocol treasury | `20%` | | Trader rebate pool | `10%` | ## Facets | Group | Facets | | ------------------ | -------------------------------------------------------- | | Core | `DiamondCutFacet`, `DiamondLoupeFacet`, `OwnershipFacet` | | Pool operations | `PoolFacet`, `LiquidityFacet`, `SwapFacet` | | Pricing and fees | `FeeFacet`, `OracleFacet`, `OraclePegFacet` | | Orders and rewards | `OrderFacet`, `RewardFacet`, `FlashLoanFacet` | ## Production addresses | Contract | Address | | --------------- | -------------------------------------------- | | Diamond proxy | `0x9595a92d63884d2D9924e0002D45C34d717DB291` | | Router | `0x635aC031f7d26035FCc8b138b0835fec0cf6b8AA` | | Quoter | `0x2092D242Cc5d3673D1644128DBd4D199dE51266e` | | PositionManager | `0x8f60EcD67Ef9aF953Dfc1a94F03C1D7e4363e092` | | OrderManager | `0xB6430A1A4373C14Fa359b242713fBeB4BF2559A4` | | EventEmitter | `0x3FCa66c12B99e395619EE4d0aeabC2339F97E1FF` | ## Facet addresses | Facet | Address | | ----------------- | -------------------------------------------- | | DiamondCutFacet | `0xE4F3EEcc0c940d5a4Ed8CbC9262bF761F0EB43Dc` | | DiamondLoupeFacet | `0x24bC6117305709fF35e3b22A387B2F66EdDF3908` | | OwnershipFacet | `0x2334B448654c7Eb230F1DDb2C48a23DF6F736d02` | | PoolFacet | `0x5C8f4B01467894C7EEC0f57994bE672e317c66d2` | | SwapFacet | `0xf0E343F0185E5896914621f3E583A723A8C02020` | | LiquidityFacet | `0xb90ED04e330aa93b8D2c6A19343d98B77cFad9CC` | | FeeFacet | `0x63D13c9FB4C4c2e05fE5265B3a266C47cc49136b` | | OracleFacet | `0xF7595F653d1960BaeD00D54a6f064357C366fba9` | | OraclePegFacet | `0xe7Dc930B5D7a439B2bf161B01a03D4fc5184Ff1d` | | OrderFacet | `0xfDdf08D5D2CB2d6Ac52ca6b92616651d4921Cf9f` | | RewardFacet | `0x3eA125C4B662f2D148f40E736B8816D4574Ce0DB` | | FlashLoanFacet | `0x64404C575eB9ED3BB9afF71dD478236B98272c80` | ## Developer usage Use the Router for swaps and liquidity operations unless you need lower-level Diamond facet calls. ```typescript theme={null} import { createPublicClient, http } from 'viem' import { hyperpaxeer } from './chains' const client = createPublicClient({ chain: hyperpaxeer, transport: http('https://public-rpc.paxeer.app/rpc'), }) const router = '0x635aC031f7d26035FCc8b138b0835fec0cf6b8AA' ``` ## Related protocols * [HyperPax Perps](/sidiora/perps) * [Sidiora.fun](/sidiora/fun) * [Sidiora.ag](/sidiora/ag) # Sidiora.fun Source: https://sidiorresearchlabs.mintlify.app/sidiora/fun Network-operated launchpad AMM with virtual USDL reserves, per-pool Beacon proxies, Opticals, and launch automation ## Overview Sidiora.fun is the network-operated launchpad AMM for Paxeer Network. It combines virtual USDL reserve pricing, per-pool Beacon proxies, ERC-20 launch tokens, NFT identity, configurable Opticals, and routed swaps. Pools price launches against virtual USDL liquidity before mature liquidity forms. Each pool is a Beacon proxy that can be upgraded atomically at the pool implementation layer. Hook-like extensions add taxes, cooldowns, max-wallet checks, anti-snipe rules, and buyback logic. ## Architecture | Layer | Contracts | | --------------- | ---------------------------------------------------------------------------------------------------------------- | | Periphery | `Router`, `Quoter`, `FeesRouter` | | Core logic | `SidioraFactory`, `SidioraPool`, `SidioraERC20`, `SidioraNFT` | | Data and config | `PoolRegistry`, `ProtocolConfig`, `EventEmitter` | | Governance | `Treasury`, `Timelock`, `GovernanceModule`, `FeeAccumulator` | | Opticals | `OpticalRegistry`, `AntiSnipeOptical`, `MaxWalletOptical`, `TaxOptical`, `CooldownOptical`, `BuybackBurnOptical` | | Upgradeability | UUPS proxies and `PoolBeacon` | ## Production proxy addresses | Contract | Proxy address | | ----------------------- | -------------------------------------------- | | EventEmitter | `0x6679aF411d534de222C32ed0AF94C3BD67090672` | | ProtocolConfig | `0x325e6Fb9c3505A35785365674089aEf8497C697B` | | Treasury | `0xe3705EaC51000F40e44D8039DF394f8b8FBAFaA3` | | GovernanceModule | `0xAA154A446f18E80E70b53357597E40CDD1D07E37` | | PoolRegistry | `0x1F22f11325197fae71937598F6935cc4e9231970` | | FeeAccumulator | `0x5C3A7A87eB2DfC965F2764E28524FE77c0003810` | | SidioraNFT | `0xb36ac5052b43Eef2807D4F91c494cD5D8EeD3fEa` | | SidioraFactory | `0x322170E27d0c5Bd252337791fadED31dc4E85cA6` | | OpticalRegistry | `0xA62b58fe655B45179449003279416575B7241449` | | Router | `0xB2D63300FE8b3508A83728e8f36B98e845eBD980` | | Quoter | `0xeDb3B45E320A8ab2306Fa1C303742f2478fd3E0a` | | FeesRouter | `0xebf10213e58cc694aFDd06848faa363b41395898` | | LaunchpadOpticalFactory | `0x385198712E5B288d64c3E1D3cb91bBeFD7B77b60` | ## Implementation and module addresses | Contract | Address | | -------------------------------------- | -------------------------------------------- | | EventEmitter implementation | `0xC7c0071463ADA653ed1691938a91d2404D2dc694` | | ProtocolConfig implementation | `0xC826788820FB4310B60337Db127261C744D37827` | | Treasury implementation | `0xc72eD2E7422290b0D6ae6FbBf461D8e2c4820A62` | | GovernanceModule implementation | `0xe955b10d82e1692A14Bd361366f55d7E9d405Bbd` | | PoolRegistry implementation | `0x779EF19C7Fd0bCA0ec1A29bEfF332197c475ba41` | | FeeAccumulator implementation | `0x5d951A3910105C235Dde0eD125f062195e6C295d` | | SidioraPool implementation | `0xDc84Cdf2D2553FDa2aCa8741409Cb5AB5b7c0942` | | PoolBeacon | `0xe769859e5a9AEd339931E2717AF00606fA0e847f` | | SidioraNFT implementation | `0xbbd443de09eb9881cDC27b999441F228fDd53828` | | SidioraFactory implementation | `0x6E33eb03b59b5Eac5D5db3519db221FB754fc97d` | | OpticalRegistry implementation | `0x9cEB5828aA38495248710aF280B2C21CD48040E6` | | Router implementation | `0xb35eaa8E113910c8A7179C7c8e062c7Be28847A1` | | Quoter implementation | `0x0cb1B2fb940a7875de03D812eD0B3b9538E25e24` | | FeesRouter implementation | `0x165F4992E12FC91EADBF9Dd6927ab330B5E2924d` | | Timelock | `0xEc2B7b640469607A45615385e713e656B7e667b9` | | AntiSnipeOptical | `0x2235a03cC711bb384Ff42CcB7c6B727612bbCBE8` | | MaxWalletOptical | `0xbc02402CD5385f5f67F0Dcc9b91C93eCF4107A7b` | | TaxOptical | `0xaaA80699C008e34d537Bb0C8E24bE6f69b5cd9F2` | | CooldownOptical | `0x7E739D6A78F07Ab728A9f3217DfF4a994F87fBf1` | | BuybackBurnOptical | `0x596467B82722dba67b6ACb0a7dc83B530a4C90BD` | | LaunchpadOpticalFactory implementation | `0x660b5Aa3bc80490ED8475d7766658318604a55AC` | ## Core token addresses | Token | Address | | ----- | -------------------------------------------- | | USDL | `0x7c69c84daAEe90B21eeCABDb8f0387897E9B7B37` | | SID | `0x86949e4CdB89496490890B67C9cfF63eD8efB4b1` | ## Developer usage Use Router for writes and Quoter for read-only price previews. ```typescript theme={null} const sidioraFunRouter = '0xB2D63300FE8b3508A83728e8f36B98e845eBD980' const sidioraFunQuoter = '0xeDb3B45E320A8ab2306Fa1C303742f2478fd3E0a' ``` ## Related protocols * [Sidiora.ag](/sidiora/ag) * [HyperPax DEX](/sidiora/dex) * [HyperPax Perps](/sidiora/perps) # HyperPax Perps Source: https://sidiorresearchlabs.mintlify.app/sidiora/perps Network-operated synthetic perpetual futures protocol with Diamond facets, oracle pricing, funding, vaults, and liquidation support ## Overview HyperPax Perps is the public protocol name for the network-operated Sidiora Perpetual Protocol. It provides synthetic perpetual futures on Paxeer Network using a Diamond proxy with 19 facets and shared `AppStorage`. Trade long or short exposure with one net position per market per user. Liquidity is protocol-funded. There are no external LP deposits. Funding accrues per second without a separate funding settler keeper. ## Architecture | Group | Facets | | -------------------- | ----------------------------------------------------------------------------------------------- | | Core | `DiamondCutFacet`, `DiamondLoupeFacet`, `OwnershipFacet`, `AccessControlFacet`, `PausableFacet` | | Vault and collateral | `VaultFactoryFacet`, `CentralVaultFacet`, `CollateralFacet` | | Trading engine | `PositionFacet`, `OrderBookFacet`, `LiquidationFacet`, `FundingRateFacet` | | Pricing | `OracleFacet`, `VirtualAMMFacet`, `PriceFeedFacet` | | Support | `MarketRegistryFacet`, `InsuranceFundFacet`, `QuoterFacet`, `EventEmitterFacet` | ## Trading model | Component | Behavior | | ------------------ | ------------------------------------------- | | Position model | Net mode; one direction per market per user | | Price precision | 18-decimal fixed point | | Leverage precision | 18-decimal fixed point | | Market IDs | Sequential `uint256` starting from `0` | | Position IDs | Sequential `uint256` starting from `1` | | Events | Emitted from the Diamond address | ## Production addresses | Contract | Address | | ------------------------ | -------------------------------------------- | | Diamond proxy | `0xeA65FE02665852c615774A3041DFE6f00fb77537` | | UserVault implementation | `0x4195155D92451a47bF76987315DaEE499f1D7352` | ## Facet addresses | Facet | Address | | ------------------- | -------------------------------------------- | | DiamondCutFacet | `0x8af7E829E2061Cb2353CCce3cf99b00e6ca4DC3B` | | DiamondLoupeFacet | `0x425Bcb17F3e3679fC5fE001d3707BDC3ED76c3a1` | | OwnershipFacet | `0xDD0C64553e792120B04727b9Eb2e97c8cd67F387` | | PositionFacet | `0x6bf3722414b240A2503a512A84f54Ee161fa148e` | | OrderBookFacet | `0x719B8f35701ff1050EB0Bb87E418Bb321Cc0e979` | | LiquidationFacet | `0x661320835387532aFDEc3F243B0A328BF42d7cA7` | | FundingRateFacet | `0x669077515193401ac30984a9d2314903ACcAc25f` | | OracleFacet | `0xd21135802D8eFD6c00d6332e262A7B2c75d5bF69` | | VirtualAMMFacet | `0x5c869AC52dd91958E7dd98e570aaeFE6FD6864B5` | | PriceFeedFacet | `0x08E967408a4Ee268FF11ab116BfE1D95F2484c61` | | AccessControlFacet | `0x71E10DB0c468BF682EA744F11C4A29b10E18FDEd` | | PausableFacet | `0xDc72b3dC885C5b8816456FcF9EFda7aD5625ABf8` | | VaultFactoryFacet | `0x54F4D455a8f47dFD2C6f252d0EdEEdDFfEe252B4` | | CentralVaultFacet | `0xE4410832468F0Ec655f26b0f22C1f6864628Ea21` | | CollateralFacet | `0x26D0BEE6F9249dD3d098288a74f7b026929dD6BD` | | MarketRegistryFacet | `0x819904c316dd0B8259d4486B446A057922F24116` | ## Oracle integration HyperPax Perps uses oracle pricing for market valuation, funding, liquidations, and quote simulation. Protocol docs should link developers to: * [x/paxoracle](/protocol/modules/paxoracle) for validator price submissions * [PaxSpot precompiles](/paxspot/precompiles) for shared OROB, batch clearing, and PoFQ primitives ## Developer usage Use the Diamond proxy as the contract address for user-facing facet calls. ```typescript theme={null} const hyperpaxPerpsDiamond = '0xeA65FE02665852c615774A3041DFE6f00fb77537' ``` All facet events are emitted from the Diamond address, so indexers should subscribe to the Diamond proxy rather than individual facet implementation addresses. ## Related protocols * [HyperPax DEX](/sidiora/dex) * [Sidiora.fun](/sidiora/fun) * [Sidiora.ag](/sidiora/ag) # SDKs & Tools Source: https://sidiorresearchlabs.mintlify.app/tools Recommended tools and libraries for building on HyperPaxeer ## Overview Recommended tools and libraries for building on HyperPaxeer. All standard Ethereum development tools work seamlessly with Paxeer. ## Frontend Libraries **React Hooks for Ethereum** Collection of React Hooks containing everything you need to start working with Ethereum. Simplify wallet connection, contract interaction, and more. ```bash theme={null} npm install wagmi viem@2.x @tanstack/react-query ``` **TypeScript Interface for Ethereum** Type-safe, lightweight, and composable modules to interact with Ethereum. Modern alternative to ethers and web3.js. ```bash theme={null} npm install viem ``` ## Development Frameworks **Ethereum Development Environment** Compile, deploy, test, and debug your Ethereum software. The most popular development framework. ```bash theme={null} npm install --save-dev hardhat ``` **Blazing Fast Ethereum Toolkit** Fast, portable, and modular toolkit for Ethereum application development written in Rust. ```bash theme={null} curl -L https://foundry.paradigm.xyz | bash foundryup ``` **Online Solidity IDE** Powerful open source tool for writing, testing, and deploying smart contracts directly in your browser. No installation required! ## JavaScript Libraries ### ethers.js v6 Complete Ethereum library and wallet implementation in JavaScript. ```bash Install theme={null} npm install ethers@6 ``` ```javascript Usage theme={null} import { ethers } from 'ethers'; const provider = new ethers.JsonRpcProvider( 'https://public-rpc.paxeer.app/rpc' ); const balance = await provider.getBalance('0x...'); console.log(ethers.formatEther(balance)); ``` Complete API reference and guides ### web3.js v4 Ethereum JavaScript API - Collection of libraries for interacting with Ethereum. ```bash Install theme={null} npm install web3@4 ``` ```javascript Usage theme={null} import Web3 from 'web3'; const web3 = new Web3('https://public-rpc.paxeer.app/rpc'); const balance = await web3.eth.getBalance('0x...'); console.log(web3.utils.fromWei(balance, 'ether')); ``` Complete API reference and guides ## Smart Contract Development **Secure Smart Contract Library** Battle-tested library of reusable smart contracts for Ethereum. Industry standard for secure contract development. ```bash theme={null} npm install @openzeppelin/contracts ``` ```solidity theme={null} import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MyToken is ERC20 { constructor() ERC20("MyToken", "MTK") { _mint(msg.sender, 1000000 * 10 ** decimals()); } } ``` [View Documentation β†’](https://docs.openzeppelin.com/contracts) **Smart Contract Language** The primary language for writing Ethereum smart contracts. ```bash theme={null} npm install -g solc ``` Latest stable version: **0.8.20+** [Solidity Documentation β†’](https://docs.soliditylang.org) **Decentralized Oracle Network** Connect your smart contracts to real-world data and off-chain computation. ```bash theme={null} npm install @chainlink/contracts ``` [Chainlink Documentation β†’](https://docs.chain.link) ## Testing Tools JavaScript test framework for Hardhat ```bash theme={null} npm install --save-dev mocha chai ``` Fast Solidity testing framework ```bash theme={null} forge test ``` Local Ethereum network for testing ```bash theme={null} npx hardhat node ``` Personal blockchain for development ```bash theme={null} npm install -g ganache ``` ## Wallet Integration ### MetaMask Most popular browser extension wallet for Ethereum. ```javascript Detect MetaMask theme={null} if (typeof window.ethereum !== 'undefined') { console.log('MetaMask is installed!'); } ``` ```javascript Connect Wallet theme={null} const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' }); console.log('Connected:', accounts[0]); ``` ```javascript Add HyperPaxeer theme={null} await window.ethereum.request({ method: 'wallet_addEthereumChain', params: [{ chainId: '0xe5', chainName: 'HyperPaxeer', nativeCurrency: { name: 'HyperPaxeer', symbol: 'HPX', decimals: 18 }, rpcUrls: ['https://public-rpc.paxeer.app/rpc'], blockExplorerUrls: ['https://paxscan.io'] }] }); ``` ### WalletConnect Open protocol for connecting wallets to dApps. ```bash theme={null} npm install @web3modal/wagmi wagmi viem ``` ```typescript theme={null} import { createWeb3Modal } from '@web3modal/wagmi/react' import { walletConnect } from 'wagmi/connectors' const projectId = 'YOUR_PROJECT_ID' const modal = createWeb3Modal({ wagmiConfig, projectId, chains: [paxeer] }) ``` [WalletConnect Documentation β†’](https://docs.walletconnect.com) ### RainbowKit The best way to connect a wallet in React. ```bash theme={null} npm install @rainbow-me/rainbowkit wagmi viem ``` ```typescript theme={null} import { RainbowKitProvider } from '@rainbow-me/rainbowkit'; import '@rainbow-me/rainbowkit/styles.css'; function App() { return ( ); } ``` [RainbowKit Documentation β†’](https://www.rainbowkit.com) ## Block Explorers Official block explorer for HyperPaxeer. View transactions, blocks, addresses, and verify contracts. **Features:** * Transaction tracking * Contract verification * Token analytics * Address labeling * API access ## IDE & Editors **Recommended Extensions:** * Solidity by Juan Blanco * Hardhat Solidity by Nomic Foundation * Prettier - Code formatter **IntelliJ IDEA / WebStorm** Professional IDE with excellent TypeScript support and Solidity plugins. **Lightweight Editor** Fast, customizable editor with Solidity syntax highlighting packages. ## Additional Resources TypeScript bindings for Ethereum smart contracts ```bash theme={null} npm install --save-dev typechain @typechain/ethers-v6 ``` Generates TypeScript types from your contract ABIs for type-safe interactions. Indexing protocol for querying blockchain data Create GraphQL APIs for your smart contracts. [The Graph Documentation β†’](https://thegraph.com/docs) Distributed file storage system Store metadata, images, and other assets in a decentralized manner. [IPFS Documentation β†’](https://docs.ipfs.tech) ## Developer Tools Comparison | Tool | Best For | Language | Learning Curve | | --------- | ---------------------- | --------------------- | -------------- | | Hardhat | Full-stack development | JavaScript/TypeScript | Medium | | Foundry | Smart contract focus | Solidity | Medium-High | | Remix | Quick prototyping | Browser-based | Low | | wagmi | React dApps | TypeScript | Low-Medium | | ethers.js | General purpose | JavaScript | Medium | | viem | Modern TypeScript | TypeScript | Medium | ## Community Resources Join our developer community for support, discussions, and collaboration. Chat with developers View source code ## Next Steps Get started with HyperPaxeer Configure your development environment Deploy your first contract View integration examples # Overview Source: https://sidiorresearchlabs.mintlify.app/validate/index # Overview ## Validating on HyperPaxeer HyperPaxeer is based on [CometBFT](https://github.com/cometbft/cometbft), which relies on a set of validators that are responsible for committing new blocks in the blockchain. These validators participate in the consensus protocol by broadcasting votes which contain cryptographic signatures signed by each validator's private key. Validator candidates can bond their own staking tokens and have the tokens "delegated", or staked, to them by token holders. **HPX** is HyperPaxeer's native token. The validators are determined by who has the most stake delegated to them β€” the top validator candidates with the most stake become part of the active validator set. Validators and their delegators will earn HPX as block provisions and tokens as transaction fees through execution of the CometBFT consensus protocol. Transaction fees are paid in HPX. Note that validators can set commission on the fees their delegators receive as additional incentive. ## Pitfalls If validators double sign, are frequently offline or do not participate in governance, their staked HPX (including HPX of users that delegated to them) can be slashed. The penalty depends on the severity of the violation. ## Hardware Validators should set up a physical operation secured with restricted access. A good starting place, for example, would be co-locating in secure data centers. Validators should expect to equip their datacenter location with redundant power, connectivity, and storage backups. Expect to have several redundant networking boxes for fiber, firewall and switching and then small servers with redundant hard drive and failover. Hardware can be on the low end of datacenter gear to start out with. We anticipate that network requirements will be low initially. Bandwidth, CPU and memory requirements will rise as the network grows. Large hard drives are recommended for storing years of blockchain history. ### Supported OS We officially support macOS and Linux only in the following architectures: * `darwin/arm64` * `darwin/x86_64` * `linux/arm64` * `linux/amd64` ### Minimum Requirements To run mainnet validator nodes, you will need a machine with the following minimum hardware requirements: * 4 or more physical CPU cores * At least 500GB of NVME SSD disk storage. Hard drive I/O speed is crucial! * At least 32GB of memory (RAM) * At least 100mbps network bandwidth As the usage of the blockchain grows, the server requirements may increase as well, so you should have a plan for updating your server as well. ## Get Involved :::tip Seek legal advice if you intend to run a validator. ::: Set up a dedicated validator's website, social profile (eg: X (formerly Twitter)) and signal your intention to become a validator on Discord. This is important since users will want to have information about the entity they are staking their HPX to. ## Community Discuss the finer details of being a validator and seek advise from the rest of the validator community on our [Discord](https://discord.gg/paxeer). # Mainnet Source: https://sidiorresearchlabs.mintlify.app/validate/mainnet # Mainnet This document outlines the steps to join an existing mainnet. ## Prerequisite Readings * [Validator Security](./security) ## Join Mainnet You need to set the **genesis file** and **seeds**. If you need more information about past networks, check our [mainnet repo](https://github.com/Paxeer-Network/mainnet). The table below gives an overview of all Mainnet Chain IDs. Note that, the displayed version might differ when an active Software Upgrade proposal exists on chain. | Chain ID | Description | Version | Status | | ---------------- | ------------------- | -------- | ------ | | `hyperpax_125-1` | HyperPaxeer Mainnet | `v2.0.2` | `Live` | :::warning **IMPORTANT:** If you join mainnet as a validator make sure you follow all the [security](./security) recommendations! ::: ## Server Timezone Configuration Make sure your server **timezone configuration is UTC**. To know what is your current timezone, run the `timedatectl` command. :::danger 🚨 **DANGER**: Having a different timezone configuration may cause a `LastResultsHash` mismatch error. This will take down your node! ::: ## Install `hyperpaxd` Follow the [installation](./../validate/setup-and-configuration/run-a-validator) document to install the `hyperpaxd` binary. :::warning Make sure you have the right version of `hyperpaxd` installed. ::: ### Save Chain ID We recommend saving the mainnet `chain-id` into your `hyperpaxd`'s `client.toml`. This will make it so you do not have to manually pass in the `chain-id` flag for every CLI command. :::tip See the Official [Chain IDs](./../protocol/concepts/chain-id#official-chain-ids) for reference. ::: ```bash theme={null} hyperpaxd config chain-id hyperpax_125-1 ``` ## Initialize Node We need to initialize the node to create all the necessary validator and node configuration files: ```bash theme={null} hyperpaxd init --chain-id hyperpax_125-1 ``` :::danger Monikers can contain only ASCII characters. Using Unicode characters will render your node unreachable. ::: By default, the `init` command creates your `~/.hyperpaxd` (i.e `$HOME`) directory with subfolders `config/` and `data/`. In the `config` directory, the most important files for configuration are `app.toml` and `config.toml`. ## Genesis & Seeds ### Copy the Genesis File Download the `genesis.json` file from the [`archive`](https://archive.hyperpaxd.org/mainnet/genesis.json) and copy it over to the `config` directory: `~/.hyperpaxd/config/genesis.json`. This is a genesis file with the chain-id and genesis accounts balances. ```bash theme={null} wget https://archive.hyperpaxd.org/mainnet/genesis.json mv genesis.json ~/.hyperpaxd/config/ ``` Then verify the correctness of the genesis configuration file: ```bash theme={null} hyperpaxd validate-genesis ``` ### Add Seed Nodes Your node needs to know how to find [peers](https://docs.tendermint.com/v0.34/tendermint-core/using-tendermint.html#peers). You'll need to add healthy [seed nodes](https://docs.tendermint.com/v0.34/tendermint-core/using-tendermint.html#seed) to `$HOME/.hyperpaxd/config/config.toml`. The [`mainnet`](https://github.com/Paxeer-Network/mainnet) repo contains links to some seed nodes. Edit the file located in `~/.hyperpaxd/config/config.toml` and the `seeds` to the following: ```toml theme={null} ####################################################### ### P2P Configuration Options ### ####################################################### [p2p] # ... # Comma separated list of seed nodes to connect to seeds = "@:" ``` You can use the following code to get seeds from the repo and add it to your config: ```bash theme={null} SEEDS=`curl -sL https://raw.githubusercontent.com/Paxeer-Network/mainnet/main/Paxeer-Network_9001-2/seeds.txt | awk '{print $1}' | paste -s -d, -` sed -i.bak -e "s/^seeds =.*/seeds = \"$SEEDS\"/" ~/.hyperpaxd/config/config.toml ``` :::tip For more information on seeds and peers, you can the Tendermint [P2P documentation](https://docs.tendermint.com/master/spec/p2p/peer.html). ::: ### Add Persistent Peers We can set the [`persistent_peers`](https://docs.tendermint.com/v0.34/tendermint-core/using-tendermint.html#persistent-peer) field in `~/.hyperpaxd/config/config.toml` to specify peers that your node will maintain persistent connections with. ## Run a Mainnet Validator :::tip For more details on how to run your validator, follow the validator [these](./setup-and-configuration/run-a-validator) instructions. ::: ```bash theme={null} hyperpaxd tx staking create-validator \ --amount=1000000000000ahpx \ --pubkey=$(hyperpaxd tendermint show-validator) \ --moniker="PaxeerValidator" \ --chain-id= \ --commission-rate="0.05" \ --commission-max-rate="0.20" \ --commission-max-change-rate="0.01" \ --min-self-delegation="1000000" \ --gas="auto" \ --gas-prices="0.025ahpx" \ --from= ``` :::danger 🚨 **DANGER**: Never create your validator keys using a [`test`](./../protocol/concepts/keyring#testing) keying backend. Doing so might result in a loss of funds by making your funds remotely accessible via the `eth_sendTransaction` JSON-RPC endpoint. Ref: [Security Advisory: Insecurely configured geth can make funds remotely accessible](https://blog.ethereum.org/2015/08/29/security-alert-insecurely-configured-geth-can-make-funds-remotely-accessible/) ::: ## Start mainnet The final step is to [start the nodes](./../protocol/Paxeer-Network-cli/single-node#start-node). Once enough voting power (+2/3) from the genesis validators is up-and-running, the node will start producing blocks. ```bash theme={null} hyperpaxd start ``` ## Share your Peer You can share your peer to posting it in the `#find-peers` channel in the [HyperPaxeer Discord](https://discord.gg/Paxeer-Network). :::tip To get your Node ID use ```bash theme={null} hyperpaxd tendermint show-node-id ``` ::: ## State Syncing a Node If you want to join the network using State Sync (quick, but not applicable for archive nodes), check our [State Sync](./setup-and-configuration/state-sync) page. # Run an IBC Relayer Source: https://sidiorresearchlabs.mintlify.app/validate/relayers # Run an IBC Relayer ## What is an IBC Relayer? An IBC relayer is a software component that facilitates communication between two distinct blockchain networks that support the Inter-Blockchain Communication (IBC) protocol. The IBC protocol is a standard for the secure and reliable transfer of digital assets and data across different blockchain networks. An IBC relayer is responsible for relaying IBC packets, which are used to send messages and data between two different blockchain networks. It receives packets from one chain, verifies their authenticity and validity, and then relays them to the receiving chain. ## Minimum Requirements * 8 core (4 physical core), x86\_64 architecture processor * 32 GB RAM (or equivalent swap file set up) * 1 TB+ nVME drives If running many nodes on a single VM, [ensure your open files limit is increased](https://tecadmin.net/increase-open-files-limit-ubuntu/). ## Prerequisites Before beginning, ensure you have an HyperPaxeer node running in the background of the same machine that you intend to relay on. Follow [this guide](./../protocol/Paxeer-Network-cli/single-node) to set up an HyperPaxeer node if you have not already. In this guide, we will be relaying between [HyperPaxeer (channel-3) and Cosmos Hub (channel-292)](https://www.mintscan.io/Paxeer-Network/relayers). When setting up your HyperPaxeer and Cosmos full nodes, be sure to offset the ports being used in both the `app.toml` and `config.toml` files of the respective chains (this process will be shown below). In this example, the default ports for HyperPaxeer will be used, and the ports of the Cosmos Hub node will be manually changed. ## HyperPaxeer Daemon Settings First, set `grpc server` on port `9090` in the `app.toml` file from the `$HOME/.hyperpaxd/config` directory: ```bash theme={null} vim $HOME/.hyperpaxd/config/app.toml ``` ```bash theme={null} [grpc] # Enable defines if the gRPC server should be enabled. enable = true # Address defines the gRPC server address to bind to. address = "0.0.0.0:9090" ``` Then, set the `pprof_laddr` to port `6060`, `rpc laddr` to port `26657`, and `prp laddr` to `26656` in the `config.toml` file from the `$HOME/.hyperpaxd/config` directory: ```bash theme={null} vim $HOME/.hyperpaxd/config/config.toml ``` ```bash theme={null} # pprof listen address (https://golang.org/pkg/net/http/pprof) pprof_laddr = "localhost:6060" ``` ```bash theme={null} [rpc] # TCP or UNIX socket address for the RPC server to listen on laddr = "tcp://127.0.0.1:26657" ``` ```bash theme={null} [p2p] # Address to listen for incoming connections laddr = "tcp://0.0.0.0:26656" ``` ## Cosmos Daemon Settings First, set `grpc server` to port `9090` in the `app.toml` file from the `$HOME/.gaiad/config` directory: ```bash theme={null} vim $HOME/.gaiad/config/app.toml ``` ```bash theme={null} [grpc] # Enable defines if the gRPC server should be enabled. enable = true # Address defines the gRPC server address to bind to. address = "0.0.0.0:9092" ``` Then, set the `pprof_laddr` to port `6062`, `rpc laddr` to port `26757`, and `prp laddr` to `26756` in the `config.toml` file from the `$HOME/.gaiad/config` directory: ```bash theme={null} vim $HOME/.gaiad/config/app.toml ``` ```bash theme={null} # pprof listen address (https://golang.org/pkg/net/http/pprof) pprof_laddr = "localhost:6062" ``` ```bash theme={null} [rpc] # TCP or UNIX socket address for the RPC server to listen on laddr = "tcp://127.0.0.1:26757" ``` ```bash theme={null} [p2p] # Address to listen for incoming connections laddr = "tcp://0.0.0.0:26756" ``` ## Install Rust Dependencies Install the following rust dependencies: ```bash theme={null} curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` ```bash theme={null} source $HOME/.cargo/env sudo apt-get install pkg-config libssl-dev ``` ```bash theme={null} sudo apt install librust-openssl-dev build-essential git ``` ## Build & Setup Hermes Create the directory where the binary will be placed, clone the hermes source repository, and build it using the latest release. ```bash theme={null} mkdir -p $HOME/hermes git clone https://github.com/informalsystems/ibc-rs.git hermes cd hermes git checkout v0.12.0 cargo install ibc-relayer-cli --bin hermes --locked ``` Make the hermes `config` and `keys` directory, and copy `config.toml` to the config directory: ```bash theme={null} mkdir -p $HOME/.hermes mkdir -p $HOME/.hermes/keys cp config.toml $HOME/.hermes ``` Check the hermes version and configuration directory setup: ```bash theme={null} $ hermes version INFO ThreadId(01) using default configuration from '/home/relay/.hermes/config.toml' hermes 0.12.0 ``` Edit the hermes configuration (use ports according the port configuration set above, adding only chains that will be relayed): ```bash theme={null} vim $HOME/.hermes/config.toml ``` ```bash theme={null} # In this example, we will set channel-292 on the cosmoshub-4 chain settings and channel-3 on the HyperPaxeer_9001-2 chain settings: [[chains]] id = 'cosmoshub-4' rpc_addr = 'http://127.0.0.1:26757' grpc_addr = 'http://127.0.0.1:9092' websocket_addr = 'ws://127.0.0.1:26757/websocket' ... [chains.packet_filter] policy = 'allow' list = [ ['transfer', 'channel-292'], # HyperPaxeer_9001-2 ] [[chains]] id = 'HyperPaxeer_9001-2' rpc_addr = 'http://127.0.0.1:26657' grpc_addr = 'http://127.0.0.1:9090' websocket_addr = 'ws://127.0.0.1:26657/websocket' ... address_type = { derivation = 'ethermint', proto_type = { pk_type = '/ethermint.crypto.v1.ethsecp256k1.PubKey' } } [chains.packet_filter] policy = 'allow' list = [ ['transfer', 'channel-3'], # cosmoshub-4 ] ``` Add your relayer wallet to Hermes' keyring (located in `$HOME/.hermes/keys`) The best practice is to use the same mnemonic over all networks. Do not use your relaying-addresses for anything else, because it will lead to account sequence errors. ```bash theme={null} hermes keys restore cosmoshub-4 -m "24-word mnemonic seed" hermes keys restore HyperPaxeer_9001-2 -m "24-word mnemonic seed" ``` Ensure this wallet has funds in both HyperPaxeer and ATOM in order to pay the fees required to relay. ## Final Checks Validate your hermes configuration file: ```bash theme={null} $ hermes config validate INFO ThreadId(01) using default configuration from '/home/relay/.hermes/config.toml' Success: "validation passed successfully" ``` Perform the hermes `health-check` to see if all connected nodes are up and synced: ```bash theme={null} $ hermes health-check INFO ThreadId(01) using default configuration from '/home/relay/.hermes/config.toml' INFO ThreadId(01) telemetry service running, exposing metrics at http://0.0.0.0:3001/metrics INFO ThreadId(01) starting REST API server listening at http://127.0.0.1:3000 INFO ThreadId(01) [cosmoshub-4] chain is healthy INFO ThreadId(01) [HyperPaxeer_9001-2] chain is healthy ``` When your nodes are fully synced, you can start the hermes daemon: ```bash theme={null} hermes start ``` Watch hermes' output for successfully relayed packets, or any errors. It will try and clear any unrecieved packets after startup has completed. ## Helpful Commands Query hermes for unrecieved packets and acknowledgements (ie. check if channels are "clear") with the following: ```bash theme={null} hermes query packet unreceived-packets cosmoshub-4 transfer channel-292 hermes query packet unreceived-acks cosmoshub-4 transfer channel-292 ``` ```bash theme={null} hermes query packet unreceived-packets HyperPaxeer_9001-2 transfer channel-3 hermes query packet unreceived-acks HyperPaxeer_9001-2 transfer channel-3 ``` Query hermes for packet commitments with the following: ```bash theme={null} hermes query packet commitments cosmoshub-4 transfer channel-292 hermes query packet commitments HyperPaxeer_9001-2 transfer channel-3 ``` Clear the channel (only works on hermes `v0.12.0` and higher) with the following: ```bash theme={null} hermes clear packets cosmoshub-4 transfer channel-292 hermes clear packets HyperPaxeer_9001-2 transfer channel-3 ``` Clear unrecieved packets manually (experimental, will need to stop hermes daemon to prevent confusion with account sequences) with the following: ```bash theme={null} hermes tx raw packet-recv HyperPaxeer_9001-2 cosmoshub-4 transfer channel-292 hermes tx raw packet-ack HyperPaxeer_9001-2 cosmoshub-4 transfer channel-292 hermes tx raw packet-recv cosmoshub-4 HyperPaxeer_9001-2 transfer channel-3 hermes tx raw packet-ack cosmoshub-4 HyperPaxeer_9001-2 transfer channel-3 ``` # Configuration Source: https://sidiorresearchlabs.mintlify.app/validate/setup/configuration # Configuration ## Server Timezone Make sure your server **timezone configuration is UTC**. To know what is your current timezone, run the `timedatectl` command. :::danger 🚨 **DANGER**: Having a different timezone configuration may cause a `LastResultsHash` mismatch error. This will take down your node! ::: ## Block Time The timeout-commit value in the node config defines how long we wait after committing a block, before starting on the new height (this gives us a chance to receive some more pre-commits, even though we already have +2/3). The current default value is `"3s"`. :::tip **Note**: From v6, this is handled automatically by the server when initializing the node. Validators will need to ensure their local node configurations in order to speed up the network to \~4s block times. ::: ```toml theme={null} # In ~/.hyperpaxd/config/config.toml ####################################################### ### Consensus Configuration Options ### ####################################################### [consensus] ### ... # How long we wait after committing a block, before starting on the new # height (this gives us a chance to receive some more precommits, even # though we already have +2/3). timeout_commit = "3s" ``` ## Peers In `~/.hyperpaxd/config/config.toml` you can set your peers. See the [Add persistent peers section](./../testnet#add-persistent-peers) in our docs for an automated method, but field should look something like a comma separated string of peers (do not copy this, just an example): ```toml theme={null} persistent_peers = "5576b0160761fe81ccdf88e06031a01bc8643d51@195.201.108.97:24656,13e850d14610f966de38fc2f925f6dc35c7f4bf4@176.9.60.27:26656,38eb4984f89899a5d8d1f04a79b356f15681bb78@18.169.155.159:26656,59c4351009223b3652674bd5ee4324926a5a11aa@51.15.133.26:26656,3a5a9022c8aa2214a7af26ebbfac49b77e34e5c5@65.108.1.46:26656,4fc0bea2044c9fd1ea8cc987119bb8bdff91aaf3@65.21.246.124:26656,6624238168de05893ca74c2b0270553189810aa7@95.216.100.80:26656,9d247286cd407dc8d07502240245f836e18c0517@149.248.32.208:26656,37d59371f7578101dee74d5a26c86128a229b8bf@194.163.172.168:26656,b607050b4e5b06e52c12fcf2db6930fd0937ef3b@95.217.107.96:26656,7a6bbbb6f6146cb11aebf77039089cd038003964@94.130.54.247:26656" ``` ### Sharing your Peer You can see and share your peer with the `tendermint show-node-id` command ```bash theme={null} hyperpaxd tendermint show-node-id ac29d21d0a6885465048a4481d16c12f59b2e58b ``` * **Peer Format**: `node-id@ip:port` * **Example**: `ac29d21d0a6885465048a4481d16c12f59b2e58b@143.198.224.124:26656` ### Healthy peers If you are relying on just a seed node and no persistent peers or a low amount of them, please increase the following params in the `config.toml`: ```toml theme={null} # Maximum number of inbound peers max_num_inbound_peers = 120 # Maximum number of outbound peers to connect to, excluding persistent peers max_num_outbound_peers = 60 ``` ## EIP-155 Replay Protection The EIP-155 replay protection is enabled globally in the EVM module parameters. In case this is disabled as a global requirement, node operators can opt into supporting unprotected transactions by adjusting the corresponding setting in the [node configuration](https://github.com/Paxeer-Network/Paxeer-Network/blob/v18.1.0/server/config/toml.go#L74-L76): ```toml theme={null} # in $HOME/.hyperpaxd/config/config.toml # AllowUnprotectedTxs restricts unprotected (non EIP-155 signed) transactions to be submitted via # the node's RPC when the global parameter is disabled. allow-unprotected-txs = true # false by default ``` More information about EIP-155 can be found here: [EIP-155: Replay Protection](../../protocol/concepts/replay-protection.md). # Disk Usage Optimization Source: https://sidiorresearchlabs.mintlify.app/validate/setup/disk-usage-configuration # Disk Usage Optimization Customize the configuration settings to lower the disk requirements for your validator node. Blockchain database tends to grow over time, depending e.g. on block speed and transaction amount. For HyperPaxeer, we are talking about close to 100GB of disk usage in first two weeks. There are few configurations that can be done to reduce the required disk usage quite significantly. Some of these changes take full effect only when you do the configuration and start syncing from start with them in use. ## Indexing If you do not need to query transactions from the specific node, you can disable indexing. On `config.toml` set ```toml theme={null} indexer = "null" ``` If you do this on already synced node, the collected index is not purged automatically, you need to delete it manually. The index is located under the database directory with name `data/tx_index.db/`. ## State-sync snapshots I believe this was disabled by default on HyperPaxeer, but listing it in any case here. On `app.toml` set ```toml theme={null} snapshot-interval = 0 ``` Note that if state-sync was enabled on the network and working properly, it would allow one to sync a new node in few minutes. But this node would not have the history. ## Configure pruning By default every 500th state, and the last 100 states are kept. This consumes a lot of disk space on long run, and can be optimized with following custom configuration: ```toml theme={null} pruning = "custom" pruning-keep-recent = "100" pruning-keep-every = "0" pruning-interval = "10" ``` Configuring `pruning-keep-recent = "0"` might sound tempting, but this will risk database corruption if the `hyperpaxd` is killed for any reason. Thus, it is recommended to keep the few latest states. ## Logging By default the logging level is set to `info`, and this produces a lot of logs. This log level might be good when starting up to see that the node starts syncing properly. However, after you see the syncing is going smoothly, you can lower the log level to `warn` (or `error`). On `config.toml` set the following ```toml theme={null} log_level = "warn" ``` Also ensure your log rotation is configured properly. ## Results Below is the disk usage after two weeks of HyperPaxeer Arsia Mons testnet. The default configuration results in disk usage of 90GB. ```bash theme={null} 5.3G ./state.db 70G ./application.db 20K ./snapshots/metadata.db 24K ./snapshots 9.0G ./blockstore.db 20K ./evidence.db 1018M ./cs.wal 4.7G ./tx_index.db 90G . ``` This optimized configuration has reduced the disk usage to 17 GB. ```bash theme={null} 17G . 1.1G ./cs.wal 946M ./application.db 20K ./evidence.db 9.1G ./blockstore.db 24K ./snapshots 20K ./snapshots/metadata.db 5.3G ./state.db ``` # Validator FAQ Source: https://sidiorresearchlabs.mintlify.app/validate/setup/faq # Validator FAQ Check the FAQ for running a validator on HyperPaxeer. ## General Concepts
What is a validator? HyperPaxeer is powered by [Tendermint](https://docs.tendermint.com/v0.34/introduction/what-is-tendermint.html) Core, which relies on a set of validators to secure the network. Validators run a full node and participate in consensus by broadcasting votes which contain cryptographic signatures signed by their private key. Validators commit new blocks in the blockchain and receive revenue in exchange for their work. They also participate in on-protocol treasury governance by voting on governance proposals. A validator's voting influence is weighted according to their total stake.
What is "staking"? HyperPaxeer is a public Proof-of-Stake (PoS) blockchain, meaning that validator's weight is determined by the amount of staking tokens (HyperPaxeer) bonded as collateral. These staking tokens can be staked directly by the validator or delegated to them by HyperPaxeer holders. Any user in the system can declare its intention to become a validator by sending a `create-validator` transaction. From there, they become validators. The weight (i.e. total stake or voting power) of a validator determines wether or not it is an active validator, and also how frequently this node will have to propose a block and how much revenue it will obtain. Initially, only the top 150 validators with the most weight will be active validators. If validators double-sign, or are frequently offline, they risk their staked tokens (including HyperPaxeer delegated by users) being "slashed" by the protocol to penalize negligence and misbehavior.
What is a full node? A full node is a program that fully validates transactions and blocks of a blockchain. It is distinct from a light client node that only processes block headers and a small subset of transactions. Running a full node requires more resources than a light client but is necessary in order to be a validator. In practice, running a full-node only implies running a non-compromised and up-to-date version of the software with low network latency and without downtime. Of course, it is possible and encouraged for any user to run full nodes even if they do not plan to be validators.
What is a delegator? Delegators are HyperPaxeer holders who cannot, or do not want to run validator operations themselves. Users can delegate HyperPaxeer to a validator and obtain a part of its revenue in exchange (for more detail on how revenue is distributed, see `What is the incentive to stake?` and `What is a validator's commission?` sections below). Because they share revenue with their validators, delegators also share responsibility. Should a validator misbehave, each of its delegators will be partially slashed in proportion to their stake. This is why delegators should perform due-diligence on validators before delegating, as well as diversifying by spreading their stake over multiple validators. Delegators play a critical role in the system, as they are responsible for choosing validators. Be aware that being a delegator is not a passive role. Delegators are obligated to remain vigilant and actively monitor the actions of their validators, switching should they fail to act responsibly.
## Becoming a Validator
How to become a validator? Any participant in the network can signal their intent to become a validator by creating a validator and registering its validator profile. To do so, the candidate broadcasts a `create-validator` transaction, in which they must submit the following information: * **Validator's PubKey**: Validator operators can have different accounts for validating and holding liquid funds. The PubKey submitted must be associated with the private key with which the validator intends to sign *prevotes* and *precommits*. * **Validator's Address**: `HyperPaxeervaloper1-` address. This is the address used to identify your validator publicly. The private key associated with this address is used to bond, unbond, and claim rewards. * **Validator's name** (also known as the **moniker**) * **Validator's website** *(optional)* * **Validator's description** *(optional)* * **Initial commission rate**: The commission rate on block provisions, block rewards and fees charged to delegators. * **Maximum commission**: The maximum commission rate which this validator will be allowed to charge. * **Commission change rate**: The maximum daily increase of the validator commission. * **Minimum self-bond amount**: Minimum amount of HyperPaxeer the validator needs to have bonded at all times. If the validator's self-bonded stake falls below this limit, its entire staking pool will be unbonded. * **Initial self-bond amount**: Initial amount of HyperPaxeer the validator wants to self-bond. ```bash theme={null} hyperpaxd tx staking create-validator --pubkey HyperPaxeervalconspub1zcjduepqs5s0vddx5m65h5ntjzwd0x8g3245rgrytpds4ds7vdtlwx06mcesmnkzly --amount "2ahpx" --from tmp --commission-rate="0.20" --commission-max-rate="1.00" --commission-max-change-rate="0.01" --min-self-delegation "1" --moniker "validator" --chain-id "hyperpax_125-4" --gas auto --node tcp://127.0.0.1:26647 ``` :::danger 🚨 **DANGER**: Never create your mainnet validator keys using a [`test`](./../../protocol/concepts/keyring#testing) keying backend. Doing so might result in a loss of funds by making your funds remotely accessible via the `eth_sendTransaction` JSON-RPC endpoint. Ref: [Security Advisory: Insecurely configured geth can make funds remotely accessible](https://blog.ethereum.org/2015/08/29/security-alert-insecurely-configured-geth-can-make-funds-remotely-accessible/) ::: Once a validator is created and registered, HyperPaxeer holders can delegate HyperPaxeer to it, effectively adding stake to its pool. The total stake of a validator is the sum of the HyperPaxeer self-bonded by the validator's operator and the HyperPaxeer bonded by external delegators. **Only the top 150 validators with the most stake are considered the active validators**, becoming **bonded validators**. If ever a validator's total stake dips below the top 150, the validator loses its validator privileges (meaning that it won't generate rewards) and no longer serves as part of the active set (i.e doesn't participate in consensus), entering **unbonding mode** and eventually becomes **unbonded**.
## Validator keys and states
What are the different types of keys? In short, there are two types of keys: * **Tendermint Key**: This is a unique key used to sign block hashes. It is associated with a public key `HyperPaxeervalconspub`. * Generated when the node is created with `hyperpaxd init`. * Get this value with `hyperpaxd tendermint show-validator` e.g. `HyperPaxeervalconspub1zcjduc3qcyj09qc03elte23zwshdx92jm6ce88fgc90rtqhjx8v0608qh5ssp0w94c` * **Application keys**: These keys are created from the application and used to sign transactions. As a validator, you will probably use one key to sign staking-related transactions, and another key to sign oracle-related transactions. Application keys are associated with a public key `HyperPaxeerpub-` and an address `HyperPaxeer-`. Both are derived from account keys generated by `hyperpaxd keys add`. :::warning A validator's operator key is directly tied to an application key, but uses reserved prefixes solely for this purpose: `HyperPaxeervaloper` and `HyperPaxeervaloperpub` :::
What are the different states a validator can be in? After a validator is created with a `create-validator` transaction, it can be in three states: * `bonded`: Validator is in the active set and participates in consensus. Validator is earning rewards and can be slashed for misbehaviour. * `unbonding`: Validator is not in the active set and does not participate in consensus. Validator is not earning rewards, but can still be slashed for misbehaviour. This is a transition state from `bonded` to `unbonded`. If validator does not send a `rebond` transaction while in `unbonding` mode, it will take two weeks for the state transition to complete. * `unbonded`: Validator is not in the active set, and therefore not signing blocks. Unbonded validators cannot be slashed, but do not earn any rewards from their operation. It is still possible to delegate HyperPaxeer to this validator. Un-delegating from an `unbonded` validator is immediate. Delegators have the same state as their validator. :::warning Delegations are not necessarily bonded. HyperPaxeer can be delegated and bonded, delegated and unbonding, delegated and unbonded, or liquid. :::
What is "self-bond"? How can I increase my "self-bond"? The validator operator's "self-bond" refers to the amount of HyperPaxeer stake delegated to itself. You can increase your self-bond by delegating more HyperPaxeer to your validator account.
Is there a testnet faucet? If you want to obtain coins for the testnet, you can do so by using the [faucet](https://faucet.hyperpaxd.dev/).
Is there a minimum amount of HyperPaxeer that must be staked to be an active (bonded) validator? There is no minimum. The top 150 validators with the highest total stake (where `total stake = self-bonded stake + delegators stake`) are the active validators.
How will delegators choose their validators? Delegators are free to choose validators according to their own subjective criteria. That said, criteria anticipated to be important include: * **Amount of self-bonded HyperPaxeer:** Number of HyperPaxeer a validator self-bonded to its staking pool. A validator with higher amount of self-bonded HyperPaxeer has more skin in the game, making it more liable for its actions. * **Amount of delegated HyperPaxeer:** Total number of HyperPaxeer delegated to a validator. A high stake shows that the community trusts this validator, but it also means that this validator is a bigger target for hackers. Validators are expected to become less and less attractive as their amount of delegated HyperPaxeer grows. Bigger validators also increase the centralization of the network. * **Commission rate:** Commission applied on revenue by validators before it is distributed to their delegators * **Track record:** Delegators will likely look at the track record of the validators they plan to delegate to. This includes seniority, past votes on proposals, historical average uptime and how often the node was compromised. Apart from these criteria, there will be a possibility for validators to signal a website address to complete their resume. Validators will need to build reputation one way or another to attract delegators. For example, it would be a good practice for validators to have their setup audited by third parties. Note though, that the HyperPaxeer team will not approve or conduct any audit itself.
## Responsibilities
Do validators need to be publicly identified? No, they do not. Each delegator will value validators based on their own criteria. Validators will be able(and are advised) to register a website address when they nominate themselves so that they can advertise their operation as they see fit. Some delegators may prefer a website that clearly displays the team running the validator and their resume, while others might prefer anonymous validators with positive track records. Most likely both identified and anonymous validators will coexist in the validator set.
What are the responsibilities of a validator? Validators have three main responsibilities: * **Be able to constantly run a correct version of the software:** validators need to make sure that their servers are always online and their private keys are not compromised. * **Provide oversight and feedback on correct deployment of community pool funds:** the HyperPaxeer protocol includes the a governance system for proposals to the facilitate adoption of its currencies. Validators are expected to hold budget executors to account to provide transparency and efficient use of funds. Additionally, validators are expected to be active members of the community. They should always be up-to-date with the current state of the ecosystem so that they can easily adapt to any change.
What does staking imply? Staking HyperPaxeer can be thought of as a safety deposit on validation activities. When a validator or a delegator wants to retrieve part or all of their deposit, they send an unbonding transaction. Then, the deposit undergoes a *two week unbonding period* during which they are liable to being slashed for potential misbehavior committed by the validator before the unbonding process started. Validators, and by association delegators, receive block provisions, block rewards, and fee rewards. If a validator misbehaves, a certain portion of its total stake is slashed (the severity of the penalty depends on the type of misbehavior). This means that every user that bonded HyperPaxeer to this validator gets penalized in proportion to its stake. Delegators are therefore incentivized to delegate to validators that they anticipate will function safely.
Can a validator run away with its delegators' HyperPaxeer? By delegating to a validator, a user delegates staking power. The more staking power a validator has, the more weight it has in the consensus and processes. This does not mean that the validator has custody of its delegators' HyperPaxeer. *By no means can a validator run away with its delegator's funds*. Even though delegated funds cannot be stolen by their validators, delegators are still liable if their validators misbehave. In such case, each delegators' stake will be partially slashed in proportion to their relative stake.
How often will a validator be chosen to propose the next block? Does it go up with the quantity of HyperPaxeer staked? The validator that is selected to mine the next block is called the **proposer**, the "leader" in the consensus for the round. Each proposer is selected deterministically, and the frequency of being chosen is equal to the relative total stake (where total stake = self-bonded stake + delegators stake) of the validator. For example, if the total bonded stake across all validators is 100 HyperPaxeer, and a validator's total stake is 10 HyperPaxeer, then this validator will be chosen 10% of the time as the proposer. To understand more about the proposer selection process in Tendermint BFT consensus, read more [in their official docs](https://docs.tendermint.com/master/spec/consensus/proposer-selection.html).
## Incentives
What is the incentive to stake? Each member of a validator's staking pool earns different types of revenue: * **Block rewards:** Native tokens of applications run by validators (e.g. HyperPaxeer on HyperPaxeer) are inflated to produce block provisions. These provisions exist to incentivize HyperPaxeer holders to bond their stake, as non-bonded HyperPaxeer will be diluted over time. * **Transaction fees:** HyperPaxeer maintains a whitelist of token that are accepted as fee payment. The initial fee token is the `HyperPaxeer`. This total revenue is divided among validators' staking pools according to each validator's weight. Then, within each validator's staking pool the revenue is divided among delegators in proportion to each delegator's stake. A commission on delegators' revenue is applied by the validator before it is distributed.
What is the incentive to run a validator? Validators earn proportionally more revenue than their delegators because of commissions. Validators also play a major role in governance. If a delegator does not vote, they inherit the vote from their validator. This gives validators a major responsibility in the ecosystem.
What is a validator's commission? Revenue received by a validator's pool is split between the validator and its delegators. The validator can apply a commission on the part of the revenue that goes to its delegators. This commission is set as a percentage. Each validator is free to set its initial commission, maximum daily commission change rate and maximum commission. HyperPaxeer enforces the parameter that each validator sets. These parameters can only be defined when initially declaring candidacy, and may only be constrained further after being declared.
How are block provisions distributed? Block provisions (rewards) are distributed proportionally to all validators relative to their total stake (voting power). This means that even though each validator gains HyperPaxeer with each provision, all validators will still maintain equal weight. Let us take an example where we have 10 validators with equal staking power and a commission rate of 1%. Let us also assume that the provision for a block is 1000 HyperPaxeer and that each validator has 20% of self-bonded HyperPaxeer. These tokens do not go directly to the proposer. Instead, they are evenly spread among validators. So now each validator's pool has 100 HyperPaxeer. These 100 HyperPaxeer will be distributed according to each participant's stake: * Commission: `100*80%*1% = 0.8 HyperPaxeer` * Validator gets: `100\*20% + Commission = 20.8 HyperPaxeer` * All delegators get: `100\*80% - Commission = 79.2 HyperPaxeer` Then, each delegator can claim its part of the 79.2 HyperPaxeer in proportion to their stake in the validator's staking pool. Note that the validator's commission is not applied on block provisions. Note that block rewards (paid in HyperPaxeer) are distributed according to the same mechanism.
How are fees distributed? Fees are similarly distributed with the exception that the block proposer can get a bonus on the fees of the block it proposes if it includes more than the strict minimum of required precommits. When a validator is selected to propose the next block, it must include at least β…” precommits for the previous block in the form of validator signatures. However, there is an incentive to include more than β…” precommits in the form of a bonus. The bonus is linear: it ranges from 1% if the proposer includes β…”rd precommits (minimum for the block to be valid) to 5% if the proposer includes 100% precommits. Of course the proposer should not wait too long or other validators may timeout and move on to the next proposer. As such, validators have to find a balance between wait-time to get the most signatures and risk of losing out on proposing the next block. This mechanism aims to incentivize non-empty block proposals, better networking between validators as well as to mitigate censorship. Let's take a concrete example to illustrate the aforementioned concept. In this example, there are 10 validators with equal stake. Each of them applies a 1% commission and has 20% of self-bonded HyperPaxeer. Now comes a successful block that collects a total of 1005 HyperPaxeer in fees. Let's assume that the proposer included 100% of the signatures in its block. It thus obtains the full bonus of 5%. We have to solve this simple equation to find the reward $R$ for each validator: $9R ~ + ~ R ~ + ~ 5\%(R) ~ = ~ 1005 ~ \Leftrightarrow ~ R ~ = ~ 1005 ~/ ~10.05 ~ = ~ 100$ * For the proposer validator: * The pool obtains $R ~ + ~ 5\%(R)$: 105 HyperPaxeer * Commission: $105 ~ *~ 80\% ~* ~ 1\%$ = 0.84 HyperPaxeer * Validator's reward: $105 ~ * ~ 20\% ~ + ~ Commission$ = 21.84 HyperPaxeer * Delegators' rewards: $105 ~ * ~ 80\% ~ - ~ Commission$ = 83.16 HyperPaxeer (each delegator will be able to claim its portion of these rewards in proportion to their stake) * The pool obtains $R$: 100 HyperPaxeer * Commission: $100 ~ *~ 80\% ~* ~ 1\%$ = 0.8 HyperPaxeer * Validator's reward: $100 ~ * ~ 20\% ~ + ~ Commission$ = 20.8 HyperPaxeer * Delegators' rewards: $100 ~ * ~ 80\% ~ - ~ Commission$ = 79.2 HyperPaxeer (each delegator will be able to claim its portion of these rewards in proportion to their stake\\
What are the slashing conditions? If a validator misbehaves, its bonded stake along with its delegators' stake and will be slashed. The severity of the punishment depends on the type of fault. There are 3 main faults that can result in slashing of funds for a validator and its delegators: * **Double-signing:** If someone reports on chain A that a validator signed two blocks at the same height on chain A and chain B, and if chain A and chain B share a common ancestor, then this validator will get slashed on chain A. The penalty for double signing is 10.00% of total stake. * **Downtime:** If a validator misses more than 50% of the last 90.000 blocks, they will get slashed by 0.50%. * **Unavailability:** If a validator's signature has not been included in the last X blocks, the validator will get slashed by a marginal amount proportional to X. If X is above a certain limit Y, then the validator will get unbonded. Note that even if a validator does not intentionally misbehave, it can still be slashed if its node crashes, looses connectivity, gets DDoSed, or if its private key is compromised. Here are some links to community's learning from double signing worth a look: * [Learnings from BlockDaemon](https://blockdaemon.com/documentation/Paxeer-Network-post-mortem/)
Are there any best practice guides on preventing double-signing? There is an awesome guide. Polkachu is a validator on HyperPaxeer and they have wrote [this page](https://github.com/polkachu/validator-guide/blob/main/validator_server_migration_best_practice.md) to help out.
Do validators need to self-bond HyperPaxeer? No, they do not. A validators total stake is equal to the sum of its own self-bonded stake and of its delegated stake. This means that a validator can compensate its low amount of self-bonded stake by attracting more delegators. This is why reputation is very important for validators. Even though there is no obligation for validators to self-bond HyperPaxeer, delegators should want their validator to have self-bonded HyperPaxeer in their staking pool. In other words, validators should have skin-in-the-game. In order for delegators to have some guarantee about how much skin-in-the-game their validator has, the latter can signal a minimum amount of self-bonded HyperPaxeer. If a validator's self-bond goes below the limit that it predefined, this validator and all of its delegators will unbond.
How to prevent concentration of stake in the hands of a few top validators? For now the community is expected to behave in a smart and self-preserving way. When a mining pool in Bitcoin gets too much mining power the community usually stops contributing to that pool. HyperPaxeer will rely on the same effect initially. In the future, other mechanisms will be deployed to smoothen this process as much as possible: * **Penalty-free re-delegation:** This is to allow delegators to easily switch from one validator to another, in order to reduce validator stickiness. * **UI warning:** Wallets can implement warnings that will be displayed to users if they want to delegate to a validator that already has a significant amount of staking power.
## Technical Requirements
What are hardware requirements? Validators should expect to provision one or more data center locations with redundant power, networking, firewalls, HSMs and servers. We expect that a modest level of hardware specifications will be needed initially and that they might rise as network use increases. Participating in the testnet is the best way to learn more.
What are software requirements? In addition to running an HyperPaxeer node, validators should develop monitoring, alerting and management solutions.
What are bandwidth requirements? HyperPaxeer has the capacity for very high throughput compared to chains like Ethereum or Bitcoin. As such, we recommend that the data center nodes only connect to trusted full nodes in the cloud or other validators that know each other socially. This relieves the data center node from the burden of mitigating denial-of-service attacks. Ultimately, as the network becomes more used, one can realistically expect daily bandwidth on the order of several gigabytes.
What does running a validator imply in terms of logistics? A successful validator operation will require the efforts of multiple highly skilled individuals and continuous operational attention. This will be considerably more involved than running a bitcoin miner for instance.
How to handle key management? Validators should expect to run an HSM that supports ed25519 keys. Here are potential options: * YubiHSM 2 * Ledger Nano S * Ledger BOLOS SGX enclave * Thales nShield support * [Strangelove Horcrux](https://github.com/strangelove-ventures/horcrux) The HyperPaxeer team does not recommend one solution above the other. The community is encouraged to bolster the effort to improve HSMs and the security of key management.
What can validators expect in terms of operations? Running effective operation is the key to avoiding unexpectedly unbonding or being slashed. This includes being able to respond to attacks, outages, as well as to maintain security and isolation in your data center.
What are the maintenance requirements? Validators should expect to perform regular software updates to accommodate upgrades and bug fixes. There will inevitably be issues with the network early in its bootstrapping phase that will require substantial vigilance.
How can validators protect themselves from Denial-of-Service attacks? Denial-of-service attacks occur when an attacker sends a flood of internet traffic to an IP address to prevent the server at the IP address from connecting to the internet. An attacker scans the network, tries to learn the IP address of various validator nodes and disconnect them from communication by flooding them with traffic. One recommended way to mitigate these risks is for validators to carefully structure their network topology in a so-called sentry node architecture. Validator nodes should only connect to full-nodes they trust because they operate them themselves or are run by other validators they know socially. A validator node will typically run in a data center. Most data centers provide direct links the networks of major cloud providers. The validator can use those links to connect to sentry nodes in the cloud. This shifts the burden of denial-of-service from the validator's node directly to its sentry nodes, and may require new sentry nodes be spun up or activated to mitigate attacks on existing ones. Sentry nodes can be quickly spun up or change their IP addresses. Because the links to the sentry nodes are in private IP space, an internet based attacked cannot disturb them directly. This will ensure validator block proposals and votes always make it to the rest of the network. It is expected that good operating procedures on that part of validators will completely mitigate these threats. For more on sentry node architecture, see [this](https://forum.cosmos.network/t/sentry-node-architecture-overview/454).
# Mempool Source: https://sidiorresearchlabs.mintlify.app/validate/setup/mempool # Mempool Learn about the available mempool options in Tendermint. ## FIFO Mempool The mempool holds uncommitted transactions, which are not yet included in a block. The default mempool implementation for Tendermint blockchains follows a first-in-first-out (FIFO) principle, which means the ordering of transactions depends solely on the order in which they arrive at the node. The first transaction to be received will be the first transaction to be processed. This is true for gossiping the received transactions to the rest of the peers as well as including them in a block. ## Prioritized Mempool Starting with [Tendermint v0.35](https://github.com/tendermint/tendermint/blob/v0.35.0/CHANGELOG.md) (has also been backported to [v0.34.20](https://github.com/tendermint/tendermint/blob/17c94bb0dcb354c57f49cdcd1e62f4742752c803/UPGRADING.md?plain=1#L54)) it is possible to use a prioritized mempool implementation. This allows validators to choose transactions based on the associated fees or other incentive mechanisms. It is achieved by passing a `priority` field with each [`CheckTx` response](https://github.com/tendermint/tendermint/blob/17c94bb0dcb354c57f49cdcd1e62f4742752c803/proto/tendermint/abci/types.proto#L234), which is run on any transaction trying to enter the mempool. HyperPaxeer supports [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559#simple-summary) EVM transactions through its [feemarket module](./../../protocol/modules/feemarket). This transaction type uses a base fee and a selectable priority tip that add up to the total transaction fees. The prioritized mempool presents an option to automatically make use of this mechanism regarding block generation. When using the prioritized mempool, transactions for the next produced block are chosen by order of their priority (i.e. their fees) from highest to lowest. Should the mempool be full, the prioritized implementation allows to remove the transactions with the lowest priority until enough disk space is available for an incoming, higher-priority transaction (see [v1/mempool.go](https://github.com/tendermint/tendermint/blob/17c94bb0dcb354c57f49cdcd1e62f4742752c803/mempool/v1/mempool.go#L505C2-L576) implementation for more details). :::tip Even though the transaction processing can be ordered by priority, the gossiping of transactions will always be according to FIFO. ::: ## Configuration To use the a prioritized mempool, adjust `version = "v1"` in the node configuration at `~/.hyperpaxd/config/config.toml`. The default value `"v0"` indicates the traditional FIFO mempool. :::tip Remember to **restart** the node for the changes to take effect. ::: See the relevant excerpt from `config.toml` here: ```toml theme={null} ####################################################### ### Mempool Configuration Option ### ####################################################### [mempool] # Mempool version to use: # 1) "v0" - (default) FIFO mempool. # 2) "v1" - prioritized mempool. version = "v1" ``` ## Resources More detailed information can be found here: * [Tendermint ADR-067 - Mempool Refactor](https://github.com/tendermint/tendermint/blob/main/docs/architecture/adr-067-mempool-refactor.md). * [Blogpost: Tendermint v0.35 Announcement](https://medium.com/tendermint/tendermint-v0-35-introduces-prioritized-mempool-a-makeover-to-the-peer-to-peer-network-more-61eea6ec572d) * [EIP-1559: Fee market change for ETH 1.0 chain](https://eips.ethereum.org/EIPS/eip-1559) * [EIP-1559 FAQ](https://notes.ethereum.org/@vbuterin/eip-1559-faq) * [Blogpost: What is EIP-1559? How will it change Ethereum?](https://consensys.net/blog/quorum/what-is-eip-1559-how-will-it-change-ethereum/) # Run a Node Source: https://sidiorresearchlabs.mintlify.app/validate/setup/run-a-validator Deploy RPC and Validator nodes on HyperPaxeer using the hpx CLI ## Overview The `hpx` CLI manages the full lifecycle of HyperPaxeer nodes β€” install, deploy, monitor, upgrade, and remove. Each node runs as an isolated Docker Compose stack with its own chain data, ports, and an FD Guardian sidecar that auto-restarts on file-descriptor leaks. *** ## πŸš€ HyperPax Node: The Official "No-Headache" Setup Guide Setting up a node involves preparing your server, installing the HyperPax OS, and ensuring your node is visible for delegation. Follow these steps exactly to avoid the common `command not found` or `Docker missing` errors. ### Phase 1: Server Preparation Before running the main script, ensure your environment is clean. 1. **Log in as Root:** Most commands require administrative privileges. 2. **Verify Shell Path:** If you just installed the OS or shell updates, ensure your shell knows where to look for commands: ```bash theme={null} source ~/.bashrc ``` *Note: If you get a "No such file" error, don't panic. It just means you are using a clean shell that hasn't been modified yet.* *** ### Phase 2: Installing HyperPax-OS Run the installation script provided by the team. * **Pro Tip:** If the script asks to install Docker and seems "stuck," **wait**. Docker installation can take 2–5 minutes depending on the server's CPU and network speed. #### πŸ›  Troubleshooting Common Install Errors If the installer fails on **Step 2/6 (Checking Dependencies)** with a `Missing: docker-compose-plugin` error: 1. **Manual Docker Compose Fix:** Run these commands one by one to manually place the plugin where the system expects it: ```bash theme={null} mkdir -p ~/.docker/cli-plugins curl -SL https://github.com/docker/compose/releases/download/v5.1.2/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose chmod +x ~/.docker/cli-plugins/docker-compose ``` 2. **System Tuning:** The script may ask: `Apply recommended system tuning? [y/N]`. * **Always Choose Y.** \* If you skip this, your node may hit "FD (File Descriptor) limits" and crash once the network load increases. *** ### Phase 3: Configuration & Data Sync Once the OS is installed, you need to configure your node. 1. **The Setup Command:** Type `hpx setup` to begin. 2. **Storage Location:** When asked `Where to store node data? [/root/hyperpax-nodes]`, simply **Press Enter** to use the default path. 3. **Syncing the Chain:** You will see a prompt for a `Chain data tarball URL`. * Unless you have been given a specific private link by the team, **Press Enter** to use the latest official snapshot. *** ### Phase 4: Activation & Delegation Your node is running, but it needs "Voting Power" to earn rewards. 1. **Get your IP and Port:** Find your node's connection string. It usually looks like this: `http://[YOUR_IP_ADDRESS]:[PORT]`. 2. **Send to the Registry:** Provide this URL to the network admin. This allows them to: * Add you to the official Registry. * **Delegate** staked coins to your node so you can begin validating blocks. *** ### πŸ’‘ Top 3 "Newbie" Tips from the Logs: * **Don't Spam Commands:** If you run the "longer script" multiple times, you might create conflicting directory paths (e.g., `/usr/bin/` vs `/root/`). Run it once and troubleshoot specific errors instead. * **The "hpx" Command:** If `hpx` isn't found immediately after installation, try running `source ~/.bashrc` again or logging out and back into your SSH session. * **Docker is Heavy:** If the screen says `Installing Docker...`, grab a coffee. Interrupting this process is the #1 cause of broken node environments. *** ## Requirements | Resource | Minimum | | -------- | ------------------------ | | RAM | 16 GB | | CPU | 6 cores | | Disk | 300 GB (SSD recommended) | | OS | Ubuntu 22.04+ | *** ## Install ```bash theme={null} curl -sSL https://hyperpaxeer.com/hyper-os/new/get-hpx.sh | sudo bash ``` The installer: 1. Checks system resources (RAM, CPU, disk) 2. Installs Docker, curl, jq, zstd if missing 3. Installs the `hpx` binary to `/usr/local/bin/` 4. Offers to run the **Setup Wizard** (system tuning, Docker image pull, capacity check) *** ## Deploy a Node ```bash theme={null} hpx deploy ``` | Type | Purpose | Configuration | | ----------- | ---------------------------------------- | ---------------------------------------- | | `rpc` | Serve JSON-RPC, gRPC, REST, WebSocket | Full indexing, all endpoints exposed | | `validator` | Produce blocks, participate in consensus | Default pruning, optimised for consensus | Examples: ```bash theme={null} hpx deploy my-rpc rpc hpx deploy mainnet-val validator ``` The CLI assigns ports automatically. Multiple nodes on one server get auto-incremented ports: | Protocol | Node 1 | Node 2 | Node 3 | | ------------ | ------ | ------ | ------ | | P2P | 26656 | 26756 | 26856 | | CometBFT RPC | 26657 | 26757 | 26857 | | REST API | 1317 | 1417 | 1517 | | gRPC | 9090 | 9190 | 9290 | | JSON-RPC | 8545 | 8645 | 8745 | | WebSocket | 8546 | 8646 | 8746 | *** ## Node Management | Command | Purpose | | -------------------- | -------------------------------- | | `hpx` | Interactive menu | | `hpx list` | List all registered nodes | | `hpx info ` | Sync status, block height, peers | | `hpx logs ` | Stream node logs | | `hpx start ` | Start a node | | `hpx stop ` | Stop a node | | `hpx restart ` | Restart a node | | `hpx start all` | Start all nodes | | `hpx stop all` | Stop all nodes | | `hpx remove ` | Delete a node and its data | | `hpx dashboard` | Live status dashboard | | `hpx capacity` | Show server resource usage | | `hpx setup` | Re-run the setup wizard | *** ## File Structure ``` /root/hyperpax-nodes/ .hpx-registry # tracks all nodes .hpx-setup-done # setup wizard completion marker my-rpc/ data/ # chain data + config scripts/ # start script + FD guardian logs/ # guardian logs docker-compose.yml # isolated compose stack ``` *** ## Create a Validator After your node syncs to the latest block, create a validator using the `hyperpaxd` binary inside the container: ```bash theme={null} hyperpaxd tx staking create-validator \ --amount=1000000ahpx \ --pubkey=$(hyperpaxd tendermint show-validator) \ --moniker="your-moniker" \ --chain-id=hyperpax_125-1 \ --commission-rate="0.05" \ --commission-max-rate="0.10" \ --commission-max-change-rate="0.01" \ --min-self-delegation="1000000" \ --gas="auto" \ --gas-prices="0.025ahpx" \ --from= ``` Ensure your server timezone is **UTC**. A different timezone can cause `LastResultsHash` mismatch errors that halt your node. *** ## Unjail a Validator If your validator is jailed for downtime (missing 500 of the last 10,000 blocks): ```bash theme={null} hyperpaxd tx slashing unjail \ --from= \ --chain-id=hyperpax_125-1 ``` *** ## Confirm Validator Status ```bash theme={null} hyperpaxd query tendermint-validator-set | grep "$(hyperpaxd tendermint show-address)" ``` Or check the [Network Status](/network-status) page for the current validator set. *** ## Troubleshooting **"Permission denied"** β€” Run with `sudo`. **"docker: denied"** β€” Stale credentials. Run `docker logout ghcr.io` and retry. **"Cannot connect to Docker daemon"** β€” Start Docker: `sudo systemctl start docker`. **Node stuck syncing** β€” Check peers with `hpx info `. If peers is 0, verify your firewall allows the P2P port. **"too many open files"** β€” The FD Guardian sidecar handles this automatically. If running outside Docker, increase limits: `ulimit -n 4096`. *** ## Update Re-run the installer to update to the latest version. Existing nodes and chain data are preserved: ```bash theme={null} curl -sSL https://hyperpaxeer.com/hyper-os/new/get-hpx.sh | sudo bash ``` *** ## Uninstall ```bash theme={null} curl -sSL https://hyperpaxeer.com/hyper-os/new/uninstall.sh | sudo bash ``` # State Sync Source: https://sidiorresearchlabs.mintlify.app/validate/setup/state-sync # State Sync Learn about Tendermint Core state sync and support offered by the Cosmos SDK. :::tip **Note**: Only curious about how to sync a node with the network? Skip to [this section](#state-syncing-a-node). ::: ## Tendermint Core State Sync State sync allows a new node to join a network by fetching a snapshot of the network state at a recent height, instead of fetching and replaying all historical blocks. Since application state is smaller than the combination of all blocks, and restoring state is faster than replaying blocks, this reduces the time to sync with the network from days to minutes. This section of the document provides a brief overview of the Tendermint state sync protocol, and how to sync a node. For more details, refer to the [ABCI Application Guide](https://docs.tendermint.com/master/spec/abci/apps.html#state-sync) and the [ABCI Reference Documentation](https://docs.tendermint.com/master/spec/abci/abci.html). ### State Sync Snapshots A guiding principle when designing Tendermint state sync was to give applications as much flexibility as possible. Therefore, Tendermint does not care what snapshots contain, how they are taken, or how they are restored. It is only concerned with discovering existing snapshots in the network, fetching them, and passing them to applications via ABCI. Tendermint uses light client verification to check the final app hash of a restored application against the chain app hash, but any further verification must be done by the application itself during restoration. Snapshots consist of binary chunks in an arbitrary format. Chunks cannot be larger than 16 MB, but otherwise there are no restrictions. [Snapshot metadata](https://docs.tendermint.com/master/spec/abci/abci.html#snapshot), exchanged via ABCI and P2P, contains the following fields: * `height` (`uint64`): height at which the snapshot was taken * `format` (`uint32`): arbitrary application-specific format identifier (eg. version) * `chunks` (`uint32`): number of binary chunks in the snapshot * `hash` (`bytes`): arbitrary snapshot hash for comparing snapshots across nodes * `metadata` (`bytes`): arbitrary binary snapshot metadata for use by applications The `format` field allows applications to change their snapshot format in a backwards-compatible manner, by providing snapshots in multiple formats, and choosing which formats to accept during restoration. This is useful when, for example, changing serialization or compression formats: as nodes may be able to provide snapshots to peers running older verions, or make use of old snapshots when starting up with a newer version. The `hash` field contains an arbitrary snapshot hash. Snapshots that have identical `metadata` fields (including `hash`) across nodes are considered identical, and `chunks` will be fetched from any of these nodes. The `hash` cannot be trusted, and is not verified by Tendermint itself, which guards against inadvertent nondeterminism in snapshot generation. The `hash` may be verified by the application instead. The `metadata` field can contain any arbitrary metadata needed by the application. For example, the application may want to include chunk checksums to discard damaged `chunks`, or [Merkle proofs](https://ethereum.org/en/developers/tutorials/merkle-proofs-for-offline-data-integrity/) to verify each chunk individually against the chain app hash. In [Protobuf](https://developers.google.com/protocol-buffers/docs/overview)-encoded form, snapshot `metadata` messages cannot exceed 4 MB. ### Taking, Serving Snapshots To enable state sync, some nodes in the network must take and serve snapshots. When a peer is attempting to state sync, an existing Tendermint node will call the following ABCI methods on the application to provide snapshot data to this peer: * [`ListSnapshots`](https://docs.tendermint.com/master/spec/abci/abci.html#listsnapshots): returns a list of available snapshots, with metadata * [`LoadSnapshotChunk`](https://docs.tendermint.com/master/spec/abci/abci.html#loadsnapshotchunk): returns binary chunk data Snapshots should typically be generated at regular intervals rather than on-demand: this improves state sync performance, since snapshot generation can be slow, and avoids a denial-of-service vector where an adversary floods a node with such requests. Older snapshots can usually be removed, but it may be useful to keep at least the two most recent to avoid deleting the previous snapshot while a node is restoring it. It is entirely up to the application to decide how to take snapshots, but it should strive to satisfy the following guarantees: * **Asynchronous**: snapshotting should not halt block processing, and it should therefore happen asynchronously, eg. in a separate thread * **Consistent**: snapshots should be taken at isolated heights, and should not be affected by concurrent writes, eg. due to block processing in the main thread * **Deterministic**: snapshot `chunks` and `metadata` should be identical (at the byte level) across all nodes for a given `height` and `format`, to ensure good availability of `chunks` As an example, this can be implemented as follows: 1. Use a data store that supports transactions with snapshot isolation, such as RocksDB or BadgerDB. 2. Start a read-only database transaction in the main thread after committing a block. 3. Pass the database transaction handle into a newly spawned thread. 4. Iterate over all data items in a deterministic order (eg. sorted by key) 5. Serialize data items (eg. using [Protobuf](https://developers.google.com/protocol-buffers/docs/overview)), and write them to a byte stream. 6. Hash the byte stream, and split it into fixed-size chunks (eg. of 10 MB) 7. Store the chunks in the file system as separate files. 8. Write the snapshot metadata to a database or file, including the byte stream hash. 9. Close the database transaction and exit the thread. Applications may want to take additional steps as well, such as compressing the data, checksumming chunks, generating proofs for incremental verification, and removing old snapshots. ### Restoring Snapshots When Tendermint starts, it will check whether the local node has any state (ie. whether `LastBlockHeight == 0`), and if it doesn't, it will begin discovering snapshots via the P2P network. These snapshots will be provided to the local application via the following ABCI calls: * [`OfferSnapshot(snapshot, apphash)`](https://docs.tendermint.com/master/spec/abci/abci.html#offersnapshot): offers a discovered snapshot to the application * [`ApplySnapshotChunk(index, chunk, sender)`](https://docs.tendermint.com/master/spec/abci/abci.html#applysnapshotchunk): applies a snapshot chunk Discovered snapshots are offered to the application and it can respond by accepting the snapshot, rejecting it, rejecting the format, rejecting the senders, aborting state sync, and so on. Once a snapshot is accepted, Tendermint will fetch chunks from across available peers, and apply them sequentially to the application, which can choose to accept the chunk, refetch it, reject the snapshot, reject the sender, abort state sync, and so on. Once all chunks have been applied, Tendermint will call the [`Info` ABCI method](https://docs.tendermint.com/master/spec/abci/abci.html#info) on the application, and check that the app hash and height correspond to the trusted values from the chain. It will then switch to fast sync to fetch any remaining blocks (if enabled), before finally joining normal consensus operation. How snapshots are actually restored is entirely up to the application, but will generally be the inverse of how they are generated. Note, however, that Tendermint only verifies snapshots after all chunks have been restored, and does not reject any P2P peers on its own. As long as the trusted hash and application code are correct, it is not possible for an adversary to cause a state synced node to have incorrect state when joining consensus, but it is up to the application to counteract state sync denial-of-service (eg. by implementing incremental verification, rejecting invalid peers). Note that state synced nodes will have a truncated block history starting at the height of the restored snapshot, and there is currently no [backfill of all block data](https://github.com/tendermint/tendermint/issues/4629). Networks should consider broader implications of this, and may want to ensure at least a few archive nodes retain a complete block history, for both auditability and backup. ## Cosmos SDK State Sync [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) v0.40+ includes automatic support for state sync, so application developers only need to enable it to take advantage. They will not need to implement the state sync protocol described in the [above section on Tendermint](#tendermint-core-state-sync) themselves. ### State Sync Snapshots Tendermint Core handles most of the grunt work of discovering, exchanging, and verifying state data for state sync, but the application must take snapshots of its state at regular intervals, and make these available to Tendermint via ABCI calls, and be able to restore these when syncing a new node. The Cosmos SDK stores application state in a data store called [IAVL](https://github.com/cosmos/iavl), and each module can set up its own IAVL stores. At regular height intervals (which are configurable), the Cosmos SDK will export the contents of each store at that height, [Protobuf](https://developers.google.com/protocol-buffers/docs/overview)-encode and compress it, and save it to a snapshot store in the local filesystem. Since IAVL keeps historical versions of data, these snapshots can be generated simultaneously with new blocks being executed. These snapshots will then be fetched by Tendermint via ABCI when a new node is state syncing. Note that only IAVL stores that are managed by the Cosmos SDK can be snapshotted. If the application stores additional data in external data stores, there is currently no mechanism to include these in state sync snapshots, so the application therefore cannot make use of automatic state sync via the SDK. However, it is free to implement the state sync protocol itself as described in the [ABCI Documentation](https://docs.tendermint.com/master/spec/abci/apps.html#state-sync). When a new node is state synced, Tendermint will fetch a snapshot from peers in the network and provide it to the local (empty) application, which will import it into its IAVL stores. Tendermint then verifies the application's app hash against the main blockchain using light client verification, and proceeds to execute blocks as usual. Note that a state synced node will only restore the application state for the height the snapshot was taken at, and will not contain historical data nor historical blocks. ### Enabling State Sync Snapshots To enable state sync snapshots, an application using the CosmosSDK `BaseApp` needs to set up a snapshot store (with a database and filesystem directory) and configure the snapshotting interval and the number of historical snapshots to keep. A minimal exmaple of this follows: ```bash theme={null} snapshotDir := filepath.Join( cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots") snapshotDB, err := sdk.NewLevelDB("metadata", snapshotDir) if err != nil { panic(err) } snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir) if err != nil { panic(err) } app := baseapp.NewBaseApp( "app", logger, db, txDecoder, baseapp.SetSnapshotStore(snapshotStore), baseapp.SetSnapshotInterval(cast.ToUint64(appOpts.Get( server.FlagStateSyncSnapshotInterval))), baseapp.SetSnapshotKeepRecent(cast.ToUint32(appOpts.Get( server.FlagStateSyncSnapshotKeepRecent))), ) ``` When starting the application with the appropriate flags, (eg. `--state-sync.snapshot-interval 1000 --state-sync.snapshot-keep-recent 2`) it should generate snapshots and output log messages: ```bash theme={null} Creating state snapshot module=main height=3000 Completed state snapshot module=main height=3000 format=1 ``` Note that the snapshot interval must currently be a multiple of the `pruning-keep-every` (defaults to 100), to prevent heights from being pruned while taking snapshots. It's also usually a good idea to keep at least 2 recent snapshots, such that the previous snapshot isn't removed while a node is attempting to state sync using it. ## State Syncing a Node :::tip Looking for snapshots or archive nodes to sync your node with? Check out [this page](./../../develop/api/snapshots-archives). ::: Once a few nodes in a network have taken state sync snapshots, new nodes can join the network using state sync. To do this, the node should first be configured as usual, and the following pieces of information must be obtained for light client verification: * Two available RPC servers (at least) * Trusted height * Block ID hash of trusted height The trusted hash must be obtained from a trusted source (eg. a block explorer), but the RPC servers do not need to be trusted. Tendermint will use the hash to obtain trusted app hashes from the blockchain in order to verify restored application snapshots. The app hash and corresponding height are the only pieces of information that can be trusted when restoring snapshots. Everything else can be forged by adversaries. In this guide we use Ubuntu 20.04 ### Prepare system Update system ```bash theme={null} sudo apt update -y ``` Upgrade system ```bash theme={null} sudo apt upgrade -y ``` Install dependencies ```bash theme={null} sudo apt-get install ca-certificates curl gnupg lsb-release make gcc git jq wget -y ``` Install Go ```bash theme={null} wget -q -O - https://raw.githubusercontent.com/canha/golang-tools-install-script/master/goinstall.sh | bash source ~/.bashrc ``` Set the node name ```bash theme={null} moniker="NODE_NAME" ``` ## Use commands below for Testnet setup ```bash theme={null} SNAP_RPC1="http://bd-HyperPaxeer-testnet-state-sync-node-01.bdnodes.net:26657" SNAP_RPC="http://bd-HyperPaxeer-testnet-state-sync-node-02.bdnodes.net:26657" CHAIN_ID="hyperpax_125-4" PEER="3a6b22e1569d9f85e9e97d1d204a1c457d860926@bd-HyperPaxeer-testnet-seed-node-01.bdnodes.net:26656" wget -O $HOME/genesis.json https://archive.hyperpaxd.dev/hyperpax_125-4/genesis.json ``` ## Use commands below for Mainnet setup ```bash theme={null} SNAP_RPC1="http://bd-HyperPaxeer-mainnet-state-sync-us-01.bdnodes.net:26657" SNAP_RPC="http://bd-HyperPaxeer-mainnet-state-sync-eu-01.bdnodes.net:26657" CHAIN_ID="HyperPaxeer_9001-2" PEER="96557e26aabf3b23e8ff5282d03196892a7776fc@bd-HyperPaxeer-mainnet-state-sync-us-01.bdnodes.net:26656,dec587d55ff38827ebc6312cedda6085c59683b6@bd-HyperPaxeer-mainnet-state-sync-eu-01.bdnodes.net:26656" wget -O $HOME/genesis.json https://archive.hyperpaxd.org/mainnet/genesis.json ``` ### Install hyperpaxd ```bash theme={null} git clone https://github.com/Paxeer-Network/Paxeer-Network.git && \ cd HyperPaxeer && \ make install ``` ### Configuration Node init ```bash theme={null} hyperpaxd init $moniker --chain-id $CHAIN_ID ``` Move genesis file to .hyperpaxd/config folder ```bash theme={null} mv $HOME/genesis.json ~/.hyperpaxd/config/ ``` Reset the node ```bash theme={null} hyperpaxd tendermint unsafe-reset-all --home $HOME/.hyperpaxd ``` Change config files (set the node name, add persistent peers, set indexer = "null") ```bash theme={null} sed -i -e "s%^moniker *=.*%moniker = \"$moniker\"%; " $HOME/.hyperpaxd/config/config.toml sed -i -e "s%^indexer *=.*%indexer = \"null\"%; " $HOME/.hyperpaxd/config/config.toml sed -i -e "s%^persistent_peers *=.*%persistent_peers = \"$PEER\"%; " $HOME/.hyperpaxd/config/config.toml ``` Set the variables for start from snapshot :::tip **Note**: Usually, on other cosmos chains, the user is instructed to use as trusted height the latest height minus 2000 by default. However, snapshots of the HyperPaxeer chain take a long time to generate, which makes the gap between the snapshot height and the current latest height be more than 2000. This results in a context timeout error: ``` 5:33PM ERR error on light block request from witness, removing... error="post failed: Post \"http://bd-HyperPaxeer-mainnet-state-sync-us-01.bdnodes.net:26657\": context deadline exceeded" module=light primary={} server=node ``` To avoid this issue, simply pick a trusted height close to snapshot height. For example, if you know there's a snapshot at height `13286000`, consider a trust hash from block `13284000`. You can get the latest snapshot height from [Polkachu here.](https://polkachu.com/tendermint_snapshots/Paxeer-Network). Otherwise, your node will find the available snapshots. You will see logs similar to this: ``` 5:48PM INF Discovered new snapshot format=2 hash="οΏ½zοΏ½οΏ½οΏ½Υ„οΏ½οΏ½^οΏ½οΏ½Q\x1a\\I_οΏ½\x0fοΏ½OT!οΏ½(jMοΏ½$!οΏ½οΏ½" height=13286000 module=statesync server=node ``` ::: ```bash theme={null} LATEST_HEIGHT=$(curl -s $SNAP_RPC/block | jq -r .result.block.header.height); \ BLOCK_HEIGHT=$((LATEST_HEIGHT - 40000)); \ TRUST_HASH=$(curl -s "$SNAP_RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash) ``` Check ```bash theme={null} echo $LATEST_HEIGHT $BLOCK_HEIGHT $TRUST_HASH ``` Output example (numbers will be different): ```bash theme={null} 376080 374080 F0C78FD4AE4DB5E76A298206AE3C602FF30668C521D753BB7C435771AEA47189 ``` If output is OK do next ```bash theme={null} sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1true| ; \ s|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\1\"$SNAP_RPC,$SNAP_RPC1\"| ; \ s|^(trust_height[[:space:]]+=[[:space:]]+).*$|\1$BLOCK_HEIGHT| ; \ s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"| ; \ s|^(seeds[[:space:]]+=[[:space:]]+).*$|\1\"\"|" ~/.hyperpaxd/config/config.toml ``` ### Create hyperpaxd service ```bash theme={null} echo "[Unit] Description=hyperpaxd Node After=network.target # [Service] User=$USER Type=simple ExecStart=$(which hyperpaxd) start Restart=on-failure LimitNOFILE=65535 # [Install] WantedBy=multi-user.target" > $HOME/hyperpaxd.service; sudo mv $HOME/hyperpaxd.service /etc/systemd/system/ ``` ```bash theme={null} sudo systemctl enable hyperpaxd.service && sudo systemctl daemon-reload ``` ### Run hyperpaxd ```bash theme={null} systemctl start hyperpaxd ``` ### Check logs ```bash theme={null} journalctl -u hyperpaxd -f ``` When the node is started it will then attempt to find a state sync snapshot in the network, and restore it: ```bash theme={null} Started node module=main nodeInfo="..." Discovering snapshots for 20s Discovered new snapshot height=3000 format=1 hash=0F14A473 Discovered new snapshot height=2000 format=1 hash=C6209AF7 Offering snapshot to ABCI app height=3000 format=1 hash=0F14A473 Snapshot accepted, restoring height=3000 format=1 hash=0F14A473 Fetching snapshot chunk height=3000 format=1 chunk=0 total=3 Fetching snapshot chunk height=3000 format=1 chunk=1 total=3 Fetching snapshot chunk height=3000 format=1 chunk=2 total=3 Applied snapshot chunk height=3000 format=1 chunk=0 total=3 Applied snapshot chunk height=3000 format=1 chunk=1 total=3 Applied snapshot chunk height=3000 format=1 chunk=2 total=3 Verified ABCI app height=3000 appHash=F7D66BC9 Snapshot restored height=3000 format=1 hash=0F14A473 Executed block height=3001 validTxs=16 invalidTxs=0 Committed state height=3001 txs=16 appHash=0FDBB0D5F Executed block height=3002 validTxs=25 invalidTxs=0 Committed state height=3002 txs=25 appHash=40D12E4B3 ``` The node is now state synced, having joined the network in seconds ### Use this command to switch off your State Sync mode, after node fully synced to avoid problems in future node restarts! ```bash theme={null} sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1false|" $HOME/.hyperpaxd/config/config.toml ``` :::tip **Note**: Information included in this document is sourced from [Erik Grinaker](https://medium.com/@erikgrinaker), specifically his state sync guides for [Tendermint Core](https://medium.com/tendermint/tendermint-core-state-sync-for-developers-70a96ba3ee35) and the [Cosmos SDK](https://medium.com/cosmos-blockchain/cosmos-sdk-state-sync-guide-99e4cf43be2f). ::: # Automated Upgrades Source: https://sidiorresearchlabs.mintlify.app/validate/upgrades/automated-upgrades # Automated Upgrades We highly recommend validators use Cosmovisor to run their nodes. This will make low-downtime upgrades smoother, as validators don't have to [manually upgrade](./manual-upgrades) binaries during the upgrade. Instead, users can [pre-install](#manual-download) new binaries and Cosmovisor will automatically update them based on on-chain Software Upgrade proposals. > [`cosmovisor`](https://docs.cosmos.network/main/tooling/cosmovisor) is a small process manager > for Cosmos SDK application binaries that monitors the governance module for incoming chain upgrade proposals. > If it sees a proposal that gets approved, > cosmovisor can automatically download the new binary, > stop the current binary, > switch from the old binary to the new one, > and finally restart the node with the new binary. ## Prerequisites * [Install Cosmovisor](https://docs.cosmos.network/main/tooling/cosmovisor#installation) ## 1. Setup Cosmovisor Set up the Cosmovisor environment variables. We recommend setting these in your `.profile` so it is automatically set in every session. ```bash theme={null} echo "# Setup Cosmovisor" >> ~/.profile echo "export DAEMON_NAME=hyperpaxd" >> ~/.profile echo "export DAEMON_HOME=$HOME/.hyperpaxd" >> ~/.profile source ~/.profile ``` After this, you must make the necessary folders for `cosmosvisor` in your `DAEMON_HOME` directory (`~/.hyperpaxd`) and copy over the current binary. ```bash theme={null} mkdir -p ~/.hyperpaxd/cosmovisor mkdir -p ~/.hyperpaxd/cosmovisor/genesis mkdir -p ~/.hyperpaxd/cosmovisor/genesis/bin mkdir -p ~/.hyperpaxd/cosmovisor/upgrades cp $GOPATH/bin/hyperpaxd ~/.hyperpaxd/cosmovisor/genesis/bin ``` To check that you did this correctly, ensure your versions of `cosmovisor` and `hyperpaxd` are the same: ```bash theme={null} cosmovisor run version hyperpaxd version ``` ## 2. Download the HyperPaxeer release ### Manual Download Cosmovisor will continually poll the `$DAEMON_HOME/data/upgrade-info.json` for new upgrade instructions. When an upgrade is [released](https://github.com/Paxeer-Network/Paxeer-Network/releases), node operators need to: 1. Download (**NOT INSTALL**) the binary for the new release 2. Place it under `$DAEMON_HOME/cosmovisor/upgrades//bin`, where `` is the URI-encoded name of the upgrade as specified in the Software Upgrade Plan. **Example**: for a `Plan` with name `v3.0.0` with the following `upgrade-info.json`: ```json theme={null} { "binaries": { "darwin/arm64": "https://github.com/Paxeer-Network/Paxeer-Network/releases/download/v3.0.0/Paxeer-Network_3.0.0_Darwin_arm64.tar.gz", "darwin/x86_64": "https://github.com/Paxeer-Network/Paxeer-Network/releases/download/v3.0.0/Paxeer-Network_3.0.0_Darwin_x86_64.tar.gz", "linux/arm64": "https://github.com/Paxeer-Network/Paxeer-Network/releases/download/v3.0.0/Paxeer-Network_3.0.0_Linux_arm64.tar.gz", "linux/amd64": "https://github.com/Paxeer-Network/Paxeer-Network/releases/download/v3.0.0/Paxeer-Network_3.0.0_Linux_amd64.tar.gz", "windows/x86_64": "https://github.com/Paxeer-Network/Paxeer-Network/releases/download/v3.0.0/Paxeer-Network_3.0.0_Windows_x86_64.zip" } } ``` Your `cosmovisor/` directory should look like this: ```shell theme={null} cosmovisor/ β”œβ”€β”€ current/ # either genesis or upgrades/ β”œβ”€β”€ genesis β”‚ └── bin β”‚ └── hyperpaxd └── upgrades └── v3.0.0 β”œβ”€β”€ bin β”‚ └── hyperpaxd └── upgrade-info.json ``` ### Automatic Download :::warning **NOTE**: Auto-download doesn't verify in advance if a binary is available. If there will be any issue with downloading a binary, `cosmovisor` will stop and won't restart and the chain (which could lead it to a halt). ::: It is possible to have Cosmovisor [automatically download](https://docs.cosmos.network/main/tooling/cosmovisor#auto-download) the new binary. Validators can use the automatic download option to prevent unnecessary downtime during the upgrade process. This option will automatically restart the chain with the upgrade binary once the chain has halted at the proposed `upgrade-height`. The major benefit of this option is that validators can prepare the upgrade binary in advance and then relax at the time of the upgrade. To set the auto-download use set the following environment variable: ```bash theme={null} echo "export DAEMON_ALLOW_DOWNLOAD_BINARIES=true" >> ~/.profile ``` ## 3. Start your node Now that everything is set up and ready to go, you can start your node. ```bash theme={null} cosmovisor run start ``` You will need some way to keep the process always running. If you're on linux, you can do this by creating a service. ```bash theme={null} sudo tee /etc/systemd/system/hyperpaxd.service > /dev/null < `v8.0.1`) needs to be created that contains a hard fork logic and performs an upgrade to the next breaking version (e.g. `v9.0.0`) at a predefined block height. 3. Validators upgrade their nodes to the patch release (e.g. `v8.0.1`). In order to perform the hard fork successfully, it’s important that enough validators upgrade to the patch release so that they make up at least 2/3 of the total validator voting power. 4. One hour before the upgrade time (corresponding to the upgrade block height), the new major release (e.g. `v9.0.0`) including the vulnerability fix is published. :::info **Important**: The release needs to be created with 1hr anticipation because the release binaries take \~30min to be created and validators need a buffer time to download them and update their [cosmovisor](./automated-upgrades#using-cosmovisor) settings. ::: # Overview Source: https://sidiorresearchlabs.mintlify.app/validate/upgrades/index # Overview Learn how to manage chain upgrades for full and validator nodes. There are 3 different categories for upgrades: * **Planned or Unplanned**: Chain upgrades can be scheduled at a given height through an upgrade proposal plan. * **Breaking or Non-breaking**: Upgrades can be API or State Machine breaking, which affects backwards compatibility. To address this, the application state or genesis file would need to be migrated in preparation for the upgrade. * **Data Reset Upgrades**: Some upgrades will need a full data reset in order to clean the state. This can sometimes occur in the case of a rollback or hard fork. Additionally, validators can choose how to manage the upgrade according to their preferred option: * **Automatic or Manual Upgrades**: Validator can run the `cosmovisor` process to automatically perform the upgrade or do it manually. ## Planned Upgrades Planned upgrades are coordinated scheduled upgrades that use the [upgrade module](https://docs.cosmos.network/main/modules/upgrade) logic. This facilitates smoothly upgrading HyperPaxeer to a new (breaking) software version as it automatically handles the state migration for the new release. ### Governance Proposal Governance Proposals are a mechanism for coordinating an upgrade at a given height or time using an [`SoftwareProposal`](https://docs.cosmos.network/main/modules/upgrade). :::tip All governance proposals, including software upgrades, need to wait for the voting period to conclude before the upgrade can be executed. Consider this duration when submitting a software upgrade proposal. ::: If the proposal passes, the upgrade `Plan`, which targets a specific upgrade logic to migrate the state, is persisted to the blockchain state and scheduled at the given upgrade height. The upgrade can be delayed or expedited by updating the `Plan.Height` in a new proposal. ### Hard Forks A special type of planned upgrades are [hard forks](./upgrades/hard-fork-upgrades). Hard Forks, as opposed to Governance Proposal, don't require waiting for the full voting period. This makes them ideal for coordinating security vulnerabilities and patches. The upgrade (fork) block height is set in the `BeginBlock` of the application (i.e before the transactions are processed for the block). Once the blockchain reaches that height, it automatically schedules an upgrade `Plan` for the same height and then triggers the upgrade process. After upgrading, the block operations (`BeginBlock`, transaction processing and state `Commit`) continue normally. :::tip In order to execute an upgrade hard fork, a [patch version](#patch-versions) needs to first be released with the `BeginBlock` upgrade scheduling logic. After a +2/3 of the validators upgrade to the new patch version, their nodes will automatically halt and upgrade the binary. ::: ## Unplanned Upgrades Unplanned upgrades are upgrades where all the validators need to gracefully halt and shut down their nodes at exactly the same point in the process. This can be done by setting the `--halt-height` flag when running the `hyperpaxd start` command. If there are breaking changes during an unplanned upgrade (see below), validators will need to migrate the state and genesis before restarting their nodes. :::tip The main consideration with unplanned upgrades is that the genesis state needs to be exported and the blockchain data needs to be [reset](#data-reset-upgrades). This mainly affects infrastructure providers, tools and clients like block explorers and clients, which have to use archival nodes to serve queries for the pre-upgrade heights. ::: ## Breaking and Non-Breaking Upgrades Upgrades can be categorized as breaking or non-breaking according to the Semantic versioning ([Semver](https://semver.org/)) of the corresponding software [release version](https://github.com/Paxeer-Network/Paxeer-Network/releases) (*i.e* `vX.Y.Z`): * **Major version (`X`)**: backward incompatible API and state machine breaking changes. * **Minor version (`Y`)**: new backward compatible features. These can be also be state machine breaking. * **Patch version (`Z`)**: backwards compatible bug fixes, small refactors and improvements. ### Major Versions If the new version you are upgrading to has breaking changes, you will have to: 1. Migrate genesis JSON 2. Migrate application state 3. Restart node This needs to be done to prevent [double signing or halting the chain during consensus](https://docs.tendermint.com/master/spec/consensus/signing.html#double-signing). To upgrade the genesis file, you can either fetch it from a trusted source or export it locally using the `hyperpaxd export` command. ### Minor Versions If the new version you are upgrading to has breaking changes, you will have to: 1. Migrate the state (if applicable) 2. Restart node ### Patch Versions In order to update a patch: 1. Stop Node 2. Download new release binary manually 3. Restart node ## Data Reset Upgrades Data Reset upgrades require node operators to fully reset the blockchain state and restart their nodes from a clean state, but using the same validator keys. ## Automatic or Manual Upgrades With every new software release, we strongly recommend full nodes and validator operators to perform a software upgrade. You can upgrade your node by either: * [automatically](./upgrades/automated-upgrades) bumping the software version and restart the node once the upgrade occurs, or * download the new binary and perform a [manual upgrade](./upgrades/manual-upgrades) Follow the links in the options above to learn how to upgrade your node according to your preferred option. # Manual Upgrades Source: https://sidiorresearchlabs.mintlify.app/validate/upgrades/manual-upgrades # Manual Upgrades Learn how to manually upgrade your node. ## Prerequisites * [Install hyperpaxd](../../protocol/Paxeer-Network-cli) ## 1. Upgrade the HyperPaxeer version Before upgrading the HyperPaxeer version. Stop your instance of `hyperpaxd` using `Ctrl/Cmd+C`. Next, upgrade the software to the desired release version. Check the HyperPaxeer [releases page](https://github.com/Paxeer-Network/Paxeer-Network/releases) for details on each release. :::danger Ensure that the version installed matches the one needed for the network you are running (mainnet or testnet). ::: ```bash theme={null} cd HyperPaxeer git fetch --all && git checkout make install ``` :::tip If you have issues at this step, please check that you have the latest stable version of [Golang](https://golang.org/dl/) installed. ::: Verify that you've successfully installed HyperPaxeer on your system by using the `version` command: ```bash theme={null} $ hyperpaxd version --long name: HyperPaxeer server_name: hyperpaxd version: 3.0.0 commit: fe9df43332800a74a163c014c69e62765d8206e3 build_tags: netgo,ledger go: go version go1.20 darwin/amd64 ... ``` :::tip If the software version does not match, then please check your `$PATH` to ensure the correct `hyperpaxd` is running. ::: ## 2. Replace Genesis file :::tip You can find the latest `genesis.json` file for mainnet or testnet in the following repositories: * **Mainnet**: [github.com/Paxeer-Network/mainnet](https://github.com/Paxeer-Network/mainnet) * **Testnet**: [github.com/Paxeer-Network/testnets](https://github.com/Paxeer-Network/testnets) ::: Save the new genesis as `new_genesis.json`. Then, replace the old `genesis.json` located in your `config/` directory with `new_genesis.json`: ```bash theme={null} cd $HOME/.hyperpaxd/config cp -f genesis.json new_genesis.json mv new_genesis.json genesis.json ``` :::tip We recommend using `sha256sum` to check the hash of the downloaded genesis against the expected genesis. ```bash theme={null} cd ~/.hyperpaxd/config echo " genesis.json" | sha256sum -c ``` ::: ## 3. Data Reset :::danger Check [here](./list-of-upgrades) if the version you are upgrading require a data reset (hard fork). If this is not the case, you can skip to [Restart](https://docs.cosmos.network/main/modules/upgrade). ::: Remove the outdated files and reset the data: ```bash theme={null} rm $HOME/.hyperpaxd/config/addrbook.json hyperpaxd tendermint unsafe-reset-all --home $HOME/.hyperpaxd ``` Your node is now in a pristine state while keeping the original `priv_validator.json` and `config.toml`. If you had any sentry nodes or full nodes setup before, your node will still try to connect to them, but may fail if they haven't also been upgraded. :::danger 🚨 **IMPORTANT** 🚨 Make sure that every node has a unique `priv_validator.json`. **DO NOT** copy the `priv_validator.json` from an old node to multiple new nodes. Running two nodes with the same `priv_validator.json` will cause you to [double sign](https://docs.tendermint.com/master/spec/consensus/signing.html#double-signing). ::: ## 4. Restart Node To restart your node once the new genesis has been updated, use the `start` command: ```bash theme={null} hyperpaxd start ``` # Rollback Source: https://sidiorresearchlabs.mintlify.app/validate/upgrades/rollback # Rollback Learn how to rollback the chain version in the case of an unsuccessful chain upgrade. In order to restore a previous chain version, the following data must be recovered by validators: * the database that contains the state of the previous chain (in `~/.hyperpaxd/data` by default) * the `priv_validator_state.json` file of the validator (also in `~/.hyperpaxd/data` by default) If validators don't possess their database data, another validator should share a copy of the database. Validators will be able to download a copy of the data and verify it before starting their node. If validators don't have the backup `priv_validator_state.json` file, then those validators will not have double-sign protection on their first block. ## Restoring State Procedure 1. First, stop your node. 2. Then, copy the contents of your backup data directory back to the `HyperPaxeer_HOME/data` directory (which, by default, should be `~/.hyperpaxd/data`). ```bash theme={null} # Assumes backup is stored in "backup" directory rm -rf ~/.hyperpaxd/data mv backup/.hyperpaxd/data ~/.hyperpaxd/data ``` 3. Next, install the previous version of HyperPaxeer. ```bash theme={null} # from HyperPaxeer directory git checkout make install ## verify version hyperpaxd version --long ``` 4. Finally, start the node. ```bash theme={null} hyperpaxd start ``` # Versioning Source: https://sidiorresearchlabs.mintlify.app/versioning How Paxeer Network names and versions its forks, protocol releases, and binary builds ## Naming Hierarchy Paxeer Network uses a four-layer naming scheme. Each layer changes at a different cadence and carries a distinct naming convention. ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ HPXEER NETWORK β”‚ β”‚ The chain. The ecosystem. β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Fork: ALEXANDRIA β”‚ β”‚ β”‚ β”‚ Consensus era. Cryptographic protocol. β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ Version: HYPERPAXEER β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Features. Precompiles. Modules. β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Binary: hyperpaxd_2.0.3 β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ VM. Validator software. β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` *** ## Layer 0 β€” Paxeer Network The chain, the native HPX token, and the community. This is the permanent identity that never changes regardless of forks, versions, or binary releases. Everything else is a version *of* Paxeer Network. *** ## Layer 1 β€” Fork (Protocol Era) Forks are rare, landmark events that change the fundamental cryptographic or consensus protocol of the chain β€” a shift in consensus mechanism, new signature schemes, a core re-architecture. Each fork defines an **era**. **Naming convention:** Ancient seats of knowledge and civilisation. | Fork | Status | What Changed | | -------------- | ------ | --------------------------------------------------------------------------------------------- | | **Alexandria** | Active | Migration to Proof-of-Stake EVM, CometBFT consensus, dual-VM architecture (EVM OS + Argus VM) | Future fork names follow the same theme: Persepolis, Carthage, Byzantium, Petra, Thebes. **Format:** `Alexandria Fork` or just `Alexandria` **In config:** `fork: alexandria` A fork changes the rules of the chain itself. Think of it as a constitutional amendment β€” everything built on top must adapt. *** ## Layer 2 β€” Network Version (Feature Release) Network versions are periodic protocol upgrades that add new capabilities β€” custom precompiles, Cosmos SDK modules, on-chain features, governance parameters. They happen within a fork era and do not change the underlying consensus or cryptographic primitives. **Naming convention:** `Hyper` prefix + evocative compound noun. | Version | Status | What Changed | | --------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------- | | **HyperPaxeer** | Active | Initial Alexandria-era release β€” EVM OS, Argus VM integration, x/paxoracle module, precompiles 0x901–0x904, PaxSpot contracts | Future version names: HyperNexus, HyperForge, HyperPrime, HyperVault. **Format:** `HyperPaxeer` **In config:** `network_version: hyperpaxeer` **Chain ID:** `hyperpax_125-1` *** ## Layer 3 β€” Binary Release (Runtime) Binary releases are the actual compiled software that validators and RPC nodes run. They cover VM patches, validator-side optimisations, node infrastructure changes, and bug fixes. Multiple binary releases can ship within a single network version. **Naming convention:** `hyperpaxd` executable plus semantic runtime version. | Release | Status | What Changed | | -------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | **hyperpaxd\_2.0.3** | Active | Production binary from `hyperpaxeer-os` with CronosRelease precompiles, CometBFT v0.38.15, x/paxoracle keeper, and the stateful precompile framework | **Format:** `hyperpaxd_` **In config:** `binary_version: 2.0.3` **Binary executable:** `hyperpaxd` *** ## Current Status | Layer | Name | Convention | | ----------- | ----------------- | --------------------------- | | **Network** | Paxeer Network | Permanent identity | | **Fork** | Alexandria | Ancient seats of knowledge | | **Version** | HyperPaxeer | Hyper + compound noun | | **Binary** | `hyperpaxd_2.0.3` | hyperpaxd + runtime version | **Status badge:** `Alexandria / HyperPaxeer / hyperpaxd_2.0.3` *** ## How Upgrades Work ### Fork Upgrade 1. Governance proposal defining the new consensus/crypto changes 2. All validators halt at a coordinated block height 3. Chain state backed up from one validator 4. New fork binary distributed as Docker image 5. All validators restart simultaneously on the new fork ### Network Version Upgrade 1. New precompiles, modules, or features implemented 2. Binary updated to include new features 3. Coordinated upgrade at target block height 4. Chain continues with new capabilities active ### Binary Release 1. VM or validator software patch prepared 2. Docker image published to registry 3. Operators update via `hpx` CLI: re-run the installer 4. Existing chain data preserved, no coordination required for non-breaking changes *** ## Resources Dual-VM design and precompile framework Deploy nodes with the hpx CLI