Expanded solutions (10 new industries) and products (Compliance & Data section) to cover full docs.lux.financial capability surface.
187 lines
8.5 KiB
TypeScript
187 lines
8.5 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
import {
|
|
getUrls,
|
|
rpcCall, ethBlockNumber,
|
|
httpStatus,
|
|
} from './helpers'
|
|
|
|
const urls = getUrls()
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Wallet Operations — RPC-level address and transaction queries
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// ── Address Format Validation ──────────────────────────────────────
|
|
test.describe('Wallet Ops — Address Format Validation', () => {
|
|
test('C-Chain returns valid hex balance for 0x address', async ({ request }) => {
|
|
const result = await rpcCall(request, urls.rpc, 'eth_getBalance', [
|
|
'0x1111111111111111111111111111111111111111', 'latest',
|
|
]) as string
|
|
expect(result).toMatch(/^0x[0-9a-fA-F]+$/)
|
|
console.log(` C-Chain balance (0x1111...): ${result}`)
|
|
})
|
|
|
|
test('X-Chain address format starts with X-', async ({ request }) => {
|
|
// Verify X-Chain is accessible; address formatting is client-side
|
|
// but we confirm X-Chain RPC responds with valid data
|
|
const result = await rpcCall(
|
|
request, urls.rpcPlatform, 'platform.getBlockchains', {},
|
|
) as { blockchains: { name: string; id: string; subnetID: string }[] }
|
|
const xChain = result.blockchains.find(c => c.name === 'X-Chain')
|
|
expect(xChain).toBeDefined()
|
|
console.log(` X-Chain ID: ${xChain!.id}`)
|
|
// X-Chain addresses are: X-lux1... (Bech32 with X- prefix)
|
|
})
|
|
|
|
test('P-Chain address format starts with P-', async ({ request }) => {
|
|
// Verify P-Chain validators have NodeID-prefixed IDs
|
|
const result = await rpcCall(
|
|
request, urls.rpcPlatform, 'platform.getCurrentValidators', { subnetID: '' },
|
|
) as { validators: { nodeID: string }[] }
|
|
expect(result.validators.length).toBeGreaterThan(0)
|
|
for (const v of result.validators) {
|
|
expect(v.nodeID).toMatch(/^NodeID-/)
|
|
}
|
|
console.log(` P-Chain validator IDs all start with NodeID-`)
|
|
// P-Chain addresses are: P-lux1... (Bech32 with P- prefix)
|
|
})
|
|
})
|
|
|
|
// ── Gas Estimation ─────────────────────────────────────────────────
|
|
test.describe('Wallet Ops — Gas Estimation', () => {
|
|
test('eth_estimateGas returns valid estimate for simple transfer', async ({ request }) => {
|
|
const result = await rpcCall(request, urls.rpc, 'eth_estimateGas', [
|
|
{
|
|
from: '0x0000000000000000000000000000000000000001',
|
|
to: '0x0000000000000000000000000000000000000002',
|
|
value: '0x0',
|
|
},
|
|
]) as string
|
|
const gas = parseInt(result, 16)
|
|
console.log(` Estimated gas (simple transfer): ${gas}`)
|
|
// Standard transfer should cost ~21000 gas
|
|
expect(gas).toBeGreaterThanOrEqual(21000)
|
|
expect(gas).toBeLessThan(100_000)
|
|
})
|
|
|
|
test('eth_estimateGas returns higher estimate for contract interaction', async ({ request }) => {
|
|
// Simulate a call with data (contract interaction)
|
|
try {
|
|
const result = await rpcCall(request, urls.rpc, 'eth_estimateGas', [
|
|
{
|
|
from: '0x0000000000000000000000000000000000000001',
|
|
to: '0x0000000000000000000000000000000000000002',
|
|
data: '0xa9059cbb0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000a',
|
|
},
|
|
]) as string
|
|
const gas = parseInt(result, 16)
|
|
console.log(` Estimated gas (with data): ${gas}`)
|
|
expect(gas).toBeGreaterThanOrEqual(21000)
|
|
} catch {
|
|
// Reverted calls are acceptable — the estimate RPC itself works
|
|
console.log(' Contract call reverted (expected for non-contract address)')
|
|
}
|
|
})
|
|
})
|
|
|
|
// ── Nonce Queries ──────────────────────────────────────────────────
|
|
test.describe('Wallet Ops — Nonce Queries', () => {
|
|
test('eth_getTransactionCount returns valid nonce for zero address', async ({ request }) => {
|
|
const result = await rpcCall(request, urls.rpc, 'eth_getTransactionCount', [
|
|
'0x0000000000000000000000000000000000000000', 'latest',
|
|
]) as string
|
|
const nonce = parseInt(result, 16)
|
|
console.log(` Nonce (zero addr): ${nonce}`)
|
|
expect(nonce).toBeGreaterThanOrEqual(0)
|
|
})
|
|
|
|
test('eth_getTransactionCount works for pending state', async ({ request }) => {
|
|
const result = await rpcCall(request, urls.rpc, 'eth_getTransactionCount', [
|
|
'0x0000000000000000000000000000000000000001', 'pending',
|
|
]) as string
|
|
const nonce = parseInt(result, 16)
|
|
console.log(` Nonce (0x01, pending): ${nonce}`)
|
|
expect(nonce).toBeGreaterThanOrEqual(0)
|
|
})
|
|
})
|
|
|
|
// ── Block and Receipt Queries ──────────────────────────────────────
|
|
test.describe('Wallet Ops — Block and Receipt Queries', () => {
|
|
test('eth_getBlockByNumber returns valid block', async ({ request }) => {
|
|
const result = await rpcCall(request, urls.rpc, 'eth_getBlockByNumber', [
|
|
'latest', false,
|
|
]) as { number: string; hash: string; timestamp: string; gasUsed: string }
|
|
expect(result).toBeDefined()
|
|
expect(result.number).toMatch(/^0x/)
|
|
expect(result.hash).toMatch(/^0x[0-9a-fA-F]{64}$/)
|
|
const blockNum = parseInt(result.number, 16)
|
|
console.log(` Latest block: ${blockNum}, hash: ${result.hash.slice(0, 18)}...`)
|
|
expect(blockNum).toBeGreaterThanOrEqual(0)
|
|
})
|
|
|
|
test('eth_getBlockByNumber with full txs returns transactions array', async ({ request }) => {
|
|
const result = await rpcCall(request, urls.rpc, 'eth_getBlockByNumber', [
|
|
'latest', true,
|
|
]) as { transactions: unknown[] }
|
|
expect(result).toBeDefined()
|
|
expect(Array.isArray(result.transactions)).toBe(true)
|
|
console.log(` Transactions in latest block: ${result.transactions.length}`)
|
|
})
|
|
|
|
test('eth_getCode returns empty for EOA', async ({ request }) => {
|
|
const result = await rpcCall(request, urls.rpc, 'eth_getCode', [
|
|
'0x0000000000000000000000000000000000000001', 'latest',
|
|
]) as string
|
|
// EOA or precompile — should return 0x or some bytecode
|
|
expect(result).toBeDefined()
|
|
console.log(` Code at 0x01: ${result.slice(0, 20)}${result.length > 20 ? '...' : ''}`)
|
|
})
|
|
})
|
|
|
|
// ── Account Storage ────────────────────────────────────────────────
|
|
test.describe('Wallet Ops — Storage Queries', () => {
|
|
test('eth_getStorageAt returns valid slot', async ({ request }) => {
|
|
const result = await rpcCall(request, urls.rpc, 'eth_getStorageAt', [
|
|
'0x0000000000000000000000000000000000000000',
|
|
'0x0',
|
|
'latest',
|
|
]) as string
|
|
expect(result).toMatch(/^0x/)
|
|
console.log(` Storage slot 0 at zero addr: ${result}`)
|
|
})
|
|
})
|
|
|
|
// ── Fee History ────────────────────────────────────────────────────
|
|
test.describe('Wallet Ops — Fee History (EIP-1559)', () => {
|
|
test('eth_feeHistory returns base fee data', async ({ request }) => {
|
|
try {
|
|
const result = await rpcCall(request, urls.rpc, 'eth_feeHistory', [
|
|
'0x4', 'latest', [25, 75],
|
|
]) as { baseFeePerGas: string[]; gasUsedRatio: number[]; oldestBlock: string }
|
|
expect(result.baseFeePerGas).toBeDefined()
|
|
expect(result.baseFeePerGas.length).toBeGreaterThan(0)
|
|
expect(result.gasUsedRatio).toBeDefined()
|
|
const oldestBlock = parseInt(result.oldestBlock, 16)
|
|
console.log(` Fee history oldest block: ${oldestBlock}`)
|
|
console.log(` Base fees: ${result.baseFeePerGas.map(f => parseInt(f, 16)).join(', ')}`)
|
|
} catch {
|
|
// eth_feeHistory may not be supported on all chains
|
|
console.log(' eth_feeHistory not supported (pre-EIP-1559 chain)')
|
|
}
|
|
})
|
|
})
|
|
|
|
// ── Max Priority Fee ───────────────────────────────────────────────
|
|
test.describe('Wallet Ops — Max Priority Fee', () => {
|
|
test('eth_maxPriorityFeePerGas returns a value', async ({ request }) => {
|
|
try {
|
|
const result = await rpcCall(request, urls.rpc, 'eth_maxPriorityFeePerGas') as string
|
|
const fee = BigInt(result)
|
|
console.log(` maxPriorityFeePerGas: ${Number(fee) / 1e9} gwei`)
|
|
expect(fee).toBeGreaterThanOrEqual(0n)
|
|
} catch {
|
|
console.log(' eth_maxPriorityFeePerGas not supported')
|
|
}
|
|
})
|
|
})
|