Technical specifications for the Aje blockchain and Web3 infrastructure domain: library inventory, core data models, type definitions, cryptographic standards, persistence schemas, and configuration. Every type, schema, and enum documented here is taken directly from
libs/aje/*source.
This document is the authoritative type reference for the Aje domain. Where the features document explains what Aje does in human terms, this document specifies exactly how it does it: the TypeScript types, Zod schemas, PostgreSQL DDL, enum values, and function signatures that new engineers need when integrating with or extending Aje libraries.
The sections are ordered from the most foundational (@aje/core primitives)
outward through the chain provider layer, RPC client, wallet specs, account
abstraction, persistence layer, V2 game integrations, and configuration.
Cross-domain integration points are documented at the end.
Domain Scope#
Aje is a library-only domain. It has no apps/ and no services/ —
ls apps/aje services/aje returns nothing. It ships 31 packages under
libs/aje/*, each a private @aje/* workspace package (version: 0.1.0,
ESM-only, "type": "module").
The domain produces composable TypeScript primitives for multi-chain blockchain
work. One package (@aje/settlement-escrow) integrates with the Concordia
domain; one set of consumers (@v2/aje-web3-cosmetic-ownership,
@v2/aje-faction-governance) lives in the V2 game project. There is no
event-bus integration in any Aje package — no domain library imports
@oshun/event-bus, and no Aje package publishes Kafka/Redis-Stream events.
Technology Stack#
| Layer | Technology |
|---|---|
| Language | TypeScript (ESM, "type": "module") |
| Runtime | Node.js (uses node:crypto for AES; otherwise pure-JS) |
| Cryptography | @noble/hashes, @noble/curves, @scure/base, @scure/bip32, @scure/bip39, @oshun/crypto |
| Persistence | Raw SQL DDL via @oshun/database (sqlRaw, ParameterizedQuery) on PostgreSQL |
| Build/Test | Nx + Vitest (vitest from the pnpm catalog) |
Cryptographic policy: cryptographic operations use the audited @noble and
@scure libraries plus the workspace @oshun/crypto package. The
encrypted-keystore module additionally uses Node's built-in node:crypto for
AES-128-CTR. No custom curve or hash implementations exist in the domain.
Library Inventory#
All 31 packages, grouped by role. Names and dependencies are from each package's
package.json.
Foundation#
| Package | Role |
|---|---|
@aje/core |
Addresses, transactions, blocks, BigNumber, crypto, ABI/RLP, events, Merkle trees, network config, errors |
@aje/chains |
Per-chain providers (Ethereum, Arbitrum, Optimism, zkSync, Polygon, Avalanche, Cardano, Solana) + abstraction |
@aje/rpc |
OshunRpcClient — multi-chain JSON-RPC client with retry, fallback, fan-out, rate limiting |
@aje/database |
PostgreSQL DDL + query builders for chain/wallet/DeFi data; block indexer; ORM-schema generator |
Wallets and accounts#
| Package | Role |
|---|---|
@aje/wallets |
HD wallets, MPC/TSS, key management, account abstraction, hardware, institutional, social login, WalletConnect, paymaster, session keys |
@aje/account-abstraction |
EIP-7702, ERC-7715, ERC-7579, ERC-6900, advanced AA infrastructure |
DeFi and finance#
| Package | Role |
|---|---|
@aje/defi |
AMM, Uniswap, Curve, lending, liquid staking, yield, derivatives, Cardano/Avalanche DeFi, safety |
@aje/payments |
Stablecoins, Circle, fiat ramps, merchant, streaming payments, CBDC |
@aje/oracles |
Chainlink (feeds, VRF, automation, functions), Pyth, RedStone, API3, custom oracle |
@aje/predictions |
Polymarket, prediction-market contracts, resolution oracles, market making, analytics |
@aje/restaking |
EigenLayer, AVS, liquid restaking tokens |
Assets#
| Package | Role |
|---|---|
@aje/nft |
ERC-721, ERC-721A, ERC-1155, token-bound accounts, soulbound, dynamic, marketplace, Cardano NFT, metadata, AI NFT |
@aje/rwa |
Security tokens, treasury tokenization, real estate, commodities, compliance, Chainlink RWA |
@aje/storage |
IPFS, Filecoin, Arweave, hybrid storage, NFT storage |
Protocol#
| Package | Role |
|---|---|
@aje/contracts |
Compilation, deployment, upgradeable proxies, OpenZeppelin, hooks, testing, fuzzing, Aiken, docs, gas optimization |
@aje/bridges |
LayerZero, Wormhole, CCIP, Axelar, custom bridge, Avalanche Warp, bridge security, aggregation |
@aje/intents |
Intent expression, solvers, CoW Protocol, UniswapX, Across, Essential |
@aje/governance |
Governor, voting, Snapshot, Tally, treasury, Aragon, Cardano governance |
@aje/identity |
DID, verifiable credentials, ENS, Lens, Farcaster, aggregation |
Infrastructure#
| Package | Role |
|---|---|
@aje/nodes |
RPC provider management, full node, Avalanche node, Cardano node, light client, validator |
@aje/security |
Static analysis, formal verification, MEV protection, runtime protection, audit tooling, incident response |
@aje/zkp |
SNARKs, Circom, STARKs, privacy circuits, Semaphore, ZKML, rollups, gnark, Plonky, ZK identity |
@aje/privacy |
Privacy pools, advanced privacy (FHE/MPC/TEE patterns) |
Ecosystem#
| Package | Role |
|---|---|
@aje/bitcoin |
Lightning, BTCPay, LSP, Lightning apps, Stacks, sBTC, BitVM, Ordinals, Runes, RGB, other L2s |
@aje/sui-move |
Sui network, Move language, Sui DeFi, Aptos |
@aje/appchains |
Conduit, Caldera, AltLayer, data availability, sequencer, config |
@aje/gaming |
MUD, World Engine, game assets, game economy, autonomous worlds, gaming L2s |
@aje/depin |
Compute, wireless, IoT, location, energy, storage, rewards DePIN networks |
@aje/agents |
Agent wallets, execution, communication, x402 micropayments, AI, frameworks, safety |
SDK and settlement#
| Package | Role |
|---|---|
@aje/sdk |
core, react, python, cli, docs sub-modules — composition layer and tooling |
@aje/settlement-escrow |
Maps Concordia escrow_release clauses to chain-ready Aje escrow deployment plans |
Dependency Hierarchy#
@aje/core declares only @oshun/types as an optional peer dependency.
Most domain packages declare @aje/core as a peer; packages that need chain
interaction additionally declare @aje/chains as a peer. Most packages also
depend on the workspace @oshun/crypto package and on @noble/* / @scure/*
crypto libraries directly.
@aje/sdk (composition layer: core / react / python / cli / docs)
│
├── peer: @aje/core, @aje/chains
│
@aje/wallets, @aje/defi, @aje/nft, @aje/contracts, @aje/oracles, @aje/rwa, …
│
├── peer: @aje/core (+ @aje/chains where chain access is needed)
│
@aje/chains ── peer: @aje/core
│
@aje/core ── optional peer: @oshun/types ; deps: @noble/*, @scure/*, @oshun/crypto
Notable exceptions:
@aje/rpchas no dependencies and no peers — it is fully self-contained.@aje/settlement-escrowdepends on@concordia/contractsandzod; it does not depend on@aje/core.@aje/databasedeclares peers@aje/coreand@oshun/databaseand has no runtimedependencies.@aje/chainsadditionally depends onabstract-level,classic-level, andmemory-level(LevelDB-family stores).
Core Data Types (@aje/core)#
@aje/core is the foundational package that all other Aje libraries build on.
It is barrel-exported from src/index.ts across nine areas: addresses,
transactions, BigNumber, blocks, crypto, ABI, events, Merkle trees, network
config, and errors. The subsections below document each area's public types in
detail.
Addresses (src/addresses/types.ts)#
Address handling is chain-discriminated: every address carries metadata about
which chain it belongs to, preventing silent cross-chain address misuse (e.g.
accidentally sending an EVM address to a Solana program). The Chain union
enumerates all supported chains; EvmChain is the EVM-compatible subset used
where only EVM chains are relevant.
type Chain =
| 'ethereum'
| 'bitcoin'
| 'cardano'
| 'avalanche'
| 'solana'
| 'polygon'
| 'arbitrum'
| 'optimism'
| 'base'
| 'bsc'
| 'avalanche-x'
| 'avalanche-p'
| 'avalanche-c';
type EvmChain =
| 'ethereum'
| 'polygon'
| 'arbitrum'
| 'optimism'
| 'base'
| 'bsc'
| 'avalanche-c';
Each chain further defines its own address format variants as literal string unions:
Chain-specific literal unions:
BitcoinAddressType—'p2pkh' | 'p2sh' | 'bech32' | 'bech32m'BitcoinNetwork—'mainnet' | 'testnet' | 'regtest'CardanoAddressType—'base' | 'pointer' | 'enterprise' | 'reward' | 'bootstrap' | 'byron'CardanoNetwork—'mainnet' | 'testnet' | 'preview' | 'preprod'AvalancheChainPrefix—'X' | 'P' | 'C'
The universal Address<M> generic wraps every supported address format in the
same shape. The meta field is a discriminated union (AddressMeta) that
narrows to the chain-specific metadata type, so consumers can inspect checksum
status, address type, witness version, stake key hash, and so on without losing
type safety.
| Type | Fields |
|---|---|
Address<M> |
raw: string, bytes: Uint8Array, meta: M |
EthereumAddressMeta |
chain: EvmChain, isChecksum: boolean, isContract?: boolean |
BitcoinAddressMeta |
chain: 'bitcoin', addressType, network, witnessVersion?: number |
CardanoAddressMeta |
chain: 'cardano', addressType, network, stakeKeyHash?: Uint8Array |
AvalancheAddressMeta |
chain: 'avalanche-x'|'-p'|'-c', chainPrefix, hrp: string |
SolanaAddressMeta |
chain: 'solana', isOnCurve: boolean, isProgramDerived?: boolean |
Supporting types: AddressBookEntry, DerivationPath (BIP-44: purpose,
coinType, account, change, index), DomainResolution, DomainResolver,
Create2Params (deployer, salt, initCodeHash). Type guards include
isEthereumAddress, isBitcoinAddress, isCardanoAddress,
isAvalancheAddress, isSolanaAddress, isEvmChain.
Transactions (src/transactions/types.ts)#
The transaction types model the lifecycle and wire format of transactions across
all supported chains. TransactionStatus tracks where a transaction is in its
lifecycle, from initial submission through eventual finality or failure:
'pending' | 'submitted' | 'confirmed' | 'failed' | 'dropped' | 'replaced'.
Ethereum has four distinct transaction formats, each introduced by a different
EIP. EthTransactionType — 'legacy' | 'eip2930' | 'eip1559' | 'eip4844'. The
EthereumTransaction union has one interface per type, ensuring that fee fields
specific to each format (e.g. maxFeePerBlobGas for EIP-4844) are only present
on the correct variant:
| Interface | Discriminant type |
Notable fields |
|---|---|---|
LegacyTransaction |
'legacy' |
gasPrice, chainId? |
Eip2930Transaction |
'eip2930' |
gasPrice, accessList: AccessListEntry[] |
Eip1559Transaction |
'eip1559' |
maxFeePerGas, maxPriorityFeePerGas, accessList |
Eip4844Transaction |
'eip4844' |
maxFeePerBlobGas, blobVersionedHashes: string[] |
All extend UnsignedTransaction<C extends Chain> (chain, type, nonce?,
data?, value?). AccessListEntry is { address, storageKeys }.
Non-EVM transaction types:
CardanoTransaction(type: 'utxo') —inputs: CardanoUtxoInput[],outputs: CardanoTxOutput[],fee,ttl?,validityStart?,certificates?,withdrawals?,metadata?,mint?,collateral?,requiredSigners?,scriptDataHash?. Values useCardanoValue(lovelace: bigint, optional nestedmultiAssetmaps).AvalancheAtomicTransaction(type: 'atomic') —sourceChain/destinationChain∈'X'|'P'|'C',inputs: AvalancheTransferableInput[],outputs: AvalancheTransferableOutput[],memo?.
Result and envelope types:
SignedTransaction<T>—transaction,signature,hash,rawSerializedTransactionSignature—r,s,v?,yParity?,publicKey?TransactionReceipt— normalized across chains:chain,hash,blockHash,blockNumber,transactionIndex,from,to,status: 'success' | 'reverted',gasUsed,effectiveGasPrice,cumulativeGasUsed,logs: TransactionLog[],contractAddress,blobGasUsed?,blobGasPrice?TransactionLog,TransactionSimulation(success,gasUsed,returnData?,error?,revertReason?,logs,stateChanges?),StateChange,ReplacementConfig,TransactionBundle
BigNumber (src/bignum/types.ts)#
On-chain token amounts are integers denominated in the token's smallest unit
(e.g. wei for ETH, lovelace for ADA). Using floating-point arithmetic for these
values would introduce rounding errors that could be financially significant.
Accordingly, all on-chain amounts in Aje use bigint; no floating point.
TokenAmount—{ value: bigint; decimals: number }FixedPoint—{ value: bigint; scale: number }(real value= value / 10^scale)CurrencyUnit—{ name, symbol, decimals, smallestUnit, chain? }RoundingMode—'floor' | 'ceil' | 'round' | 'trunc'
Pre-configured CurrencyUnit constants: ETH_UNIT, ADA_UNIT, AVAX_UNIT,
SOL_UNIT, USDC_UNIT, USDT_UNIT, BTC_UNIT, WBTC_UNIT, DAI_UNIT.
Factory/utility functions: tokenAmount, fixedPoint, currencyUnit,
tokenAmountToFixedPoint, fixedPointToTokenAmount, tokenAmountsEqual,
compareTokenAmounts (the last two throw if decimals differ).
Blocks (src/blocks/types.ts)#
Different blockchains identify and structure blocks in fundamentally different
ways — Ethereum uses block numbers, Cardano uses slots within epochs, and
Avalanche uses heights within subnets. The block types in @aje/core provide a
unified layer over these differences while still exposing chain-specific fields
where necessary.
BlockHeight (height, optional epoch, slotInEpoch) abstracts block number
/ Cardano slot / Avalanche height. BlockTag —
'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'. BlockIdentifier is
a discriminated union of {type:'number'}, {type:'tag'}, {type:'hash'}.
Consensus proofs (ConsensusProof union): ProofOfWork (nonce, mixHash,
difficulty, totalDifficulty?), ProofOfStake (proposer, slot?,
epoch?, attestationCount?, randaoReveal?), DelegatedProofOfStake
(delegate, round?, isElected, delegatedStake?).
Headers: BlockHeader<P> base plus EthereumBlockHeader (EIP-1559
baseFeePerGas?, EIP-4844 blobGasUsed?/excessBlobGas?/
parentBeaconBlockRoot?, withdrawalsRoot?), CardanoBlockHeader (poolId,
operationalCertificate?, protocolVersion), AvalancheBlockHeader
(subChain, chainId, blockSize). Blocks: Block<H>, EthereumBlock
(uncles, withdrawals?, blobSidecars?), CardanoBlock, AvalancheBlock.
EIP-4844 blob types: Blob (data 128 KiB, kzgCommitment 48 B, kzgProof 48
B), BlobSidecar, BlockBlobSidecars. Genesis types: GenesisAllocation,
GenesisConfig, GenesisChainConfig (per-fork activation blocks from Homestead
through Cancun). Withdrawal (post-Shanghai). Constructor helpers:
blockHeight, blockByNumber, blockByTag, blockByHash.
Network configuration (src/network/types.ts, src/network/chains.ts)#
ChainId = number. NetworkType —
'mainnet' | 'testnet' | 'devnet' | 'local'. ConsensusType —
'pow' | 'pos' | 'dpos' | 'poa' | 'pbft'.
ChainConfig carries chainId, name, networkType, consensus,
nativeCurrency, rpcEndpoints, blockExplorers, optional forks,
averageBlockTime, confirmations, isEvm, and parent
({ chainId, type: 'L2' | 'sidechain' | 'subnet' }). Supporting types:
NativeCurrency, BlockExplorer, RpcEndpoint, GasPriceOracle, FeeData,
HardFork, NetworkHealth, NetworkHealthMonitor.
Pre-built ChainConfig constants in chains.ts: ETHEREUM_MAINNET (1),
ETHEREUM_SEPOLIA (11155111), POLYGON_MAINNET (137), ARBITRUM_ONE (42161),
OPTIMISM (10), BASE_MAINNET (8453), BSC_MAINNET (56), AVALANCHE_C_CHAIN
(43114), aggregated in the CHAINS record. Helper functions:
estimateConfirmationTime, isEip1559Chain, suggestPriorityFee.
ABI (src/abi/types.ts)#
SolidityType is a string template union covering address, bool, string,
bytes, bytes1–bytes32, uint8–uint256, int8–int256, tuple, plus a
string catch-all for array types.
ABI items: ABIFunction, ABIEvent, ABIError, ABIConstructor,
ABIFallback, ABIReceive (union ABIItem; ABI = readonly ABIItem[]).
ABIFunction.stateMutability ∈ 'pure' | 'view' | 'nonpayable' | 'payable'.
ABIParameter carries name, type, optional indexed, nested components?,
internalType?. ABITypeCategory — 'static' | 'dynamic'. Decoded shapes:
DecodedParameter, DecodedEventLog, DecodedError. HumanReadableABI is a
signature-string alias. The module also provides RLP encoding
(src/abi/rlp.ts), an encoder, decoder, and parser.
Events (src/events/types.ts)#
EventLog (full log: address, topics, data, blockNumber, blockHash,
transactionHash, transactionIndex, logIndex, removed),
DecodedEvent<T>, EventFilter, EventSubscription, EventCallback<T>,
EventProvider, TransferEvent, ApprovalEvent, PaginatedEventQuery,
PaginatedEventResult.
These are blockchain log-event types — they describe on-chain event logs, not a service event bus. Aje publishes no inter-domain messages.
Errors (src/errors/types.ts)#
Precise error handling is critical in a financial domain — catching a generic
Error and retrying blindly can double-spend, whereas catching a specific
RateLimitError and backing off is the correct behavior. The error module
provides two numeric enums for well-known error codes, plus a typed class
hierarchy rooted at BlockchainError.
RpcErrorCode maps the numeric codes from the JSON-RPC 2.0 spec and the
Ethereum provider spec to named constants. The standard JSON-RPC 2.0 range
covers PARSE_ERROR = -32700 through INTERNAL_ERROR = -32603; the server
range covers -32000 through -32006; and the Ethereum EIP-1474/1193 provider
codes add USER_REJECTED_REQUEST = 4001, UNAUTHORIZED = 4100,
UNSUPPORTED_METHOD = 4200, DISCONNECTED = 4900, CHAIN_DISCONNECTED = 4901.
PanicCode maps the numeric panic codes that Solidity emits when an assertion
fails, to named constants: ASSERT_FAILURE = 0x01,
ARITHMETIC_OVERFLOW = 0x11, DIVISION_BY_ZERO = 0x12,
ENUM_CONVERSION_OUT_OF_RANGE = 0x21, STORAGE_ENCODING_ERROR = 0x22,
POP_EMPTY_ARRAY = 0x31, ARRAY_OUT_OF_BOUNDS = 0x32,
MEMORY_OVERFLOW = 0x41, ZERO_INITIALIZED_FUNCTION = 0x51.
The error class hierarchy gives consuming code fine-grained catch targets. All
classes are rooted at BlockchainError (code: number, chainId?,
details?):
| Class | Extends | Extra fields |
|---|---|---|
BlockchainError |
Error |
code, chainId?, details? |
TransactionError |
BlockchainError |
txHash? |
RpcError |
BlockchainError |
rpcCode, data? |
ValidationError |
BlockchainError |
field?, value? |
ContractError |
BlockchainError |
contractAddress?, method? |
NetworkError |
BlockchainError |
url? |
AuthenticationError |
BlockchainError |
(code UNAUTHORIZED) |
InsufficientFundsError |
TransactionError |
required?, available? |
NonceError |
TransactionError |
expectedNonce?, providedNonce? |
GasEstimationError |
TransactionError |
gasLimit? |
RevertError |
ContractError |
reason?, decodedData? |
PanicError |
ContractError |
panicCode: PanicCode |
RetryStrategy config: maxRetries, baseDelay, maxDelay,
backoffMultiplier.
Cryptography (src/crypto/)#
@aje/core re-exports the full audited cryptographic surface used across Aje.
All functions delegate to @noble/*, @scure/*, or Node's node:crypto — no
custom implementations. The exports cover hashing, signing, encryption, key
derivation, and the types that go with them. Hashing: keccak256, sha256,
sha512, blake2b, ripemd160, hash160Hex, doubleSha256, hashMessage,
EIP-712 helpers (encodeType, typeHash, hashTypedData). Signatures:
secp256k1 (secp256k1Sign/Verify/GetPublicKey, ecrecover,
ecrecoverAddress), ed25519, BLS12-381 (bls12381Sign/Verify/
GetPublicKey/AggregateSignatures), Schnorr. Encryption: aesGcmEncrypt/
Decrypt, ECIES, pbkdf2, scryptDerive. Mnemonics/HD: generateMnemonic,
validateMnemonic, mnemonicToSeed, hdKeyFromSeed, deriveHDKey,
DERIVATION_PATHS, HARDENED_OFFSET. Crypto types: PoseidonHasher,
EIP712Domain, EIP712Types, EIP712TypedData, Secp256k1Signature,
Ed25519Signature, SchnorrSignature, AesGcmEncrypted, EciesEncrypted,
ScryptOptions, Argon2Options, MnemonicStrength, HDKeyNode.
Multi-Chain Provider Layer (@aje/chains)#
@aje/chains is structured as one named namespace per chain, each containing
the provider, RPC client, gas estimator, bridge/messaging helpers, and any
chain-specific modules. For example, the ethereum namespace has flashbots.ts
and multicall.ts; the solana namespace has jito.ts, program.ts, and
token.ts; the cardano namespace has plutus.ts, hydra.ts, and
governance.ts; and the polygon namespace also exports linea, scroll, and
starknet. The top-level package re-exports these via export * as ethereum,
export * as arbitrum, etc., plus export * as abstraction.
Chain abstraction interface (src/abstraction/types.ts)#
The abstraction namespace defines the ChainProvider interface that every chain
module must implement. This is what application code uses when it doesn't need
to know which specific chain it's talking to — the interface provides a
consistent API for block queries, balance lookups, transaction submission, and
health checks regardless of the underlying chain.
ChainType — 'evm' | 'cardano' | 'solana' | 'avalanche-x' | 'avalanche-p'.
ChainId here is a string (e.g. "ethereum:1", "solana:mainnet-beta"),
distinct from the numeric ChainId in @aje/core/network.
ChainProvider is the unified adapter interface every chain module implements:
interface ChainProvider {
readonly chain: ChainInfo;
readonly capabilities: ChainCapabilities;
getBlockHeight(): Promise<bigint>;
getBalance(address: string): Promise<bigint>;
getNonce(address: string): Promise<bigint>;
estimateGas(tx: UnifiedTransactionRequest): Promise<GasEstimate>;
sendTransaction(signedTx: string): Promise<string>;
getTransactionReceipt(
txHash: string
): Promise<UnifiedTransactionReceipt | null>;
getLogs(query: LogQuery): Promise<readonly UnifiedLog[]>;
healthCheck(): Promise<ProviderHealthStatus>;
destroy(): void;
}
Supporting types: ChainInfo, NativeCurrency, ChainCapabilities (feature
flags: smartContracts, nativeMultiAsset, accountAbstraction, l2Bridge,
zkProofs, utxoModel, eip1559, eip4844, websocketSubscriptions,
staking, governance, crossChainMessaging, custom[]),
ChainProviderConfig, UnifiedTransactionRequest, GasSpeed
('slow' | 'standard' | 'fast'), GasEstimate, GasSpeedEstimate,
UnifiedTransactionReceipt, UnifiedLog, EventFilter, LogQuery,
EventSubscription, BalanceQuery, BalanceResult, NameSystem
('ens' | 'unstoppable' | 'ada-handle' | 'sns' | 'custom'), ResolvedAddress,
AddressValidation, ProviderHealthStatus, AggregatedHealthStatus,
NonceState, ChainSwitchResult, MultiChainBatch, BatchStatus
('pending' | 'submitting' | 'partial' | 'completed' | 'failed'),
BatchTransactionResult, OptimizationHint, OptimizationCategory,
MigrationPlan / MigrationStep / MigrationStepType / MigrationStepStatus
/ MigrationStatus, FallbackConfig, RpcEndpointState. The abstraction
package also ships chain-registry.ts, transaction-builder.ts,
address-resolver.ts, and unified-provider.ts.
RPC Client (@aje/rpc)#
@aje/rpc is the only Aje package with no dependencies and no peers. It is
fully self-contained by design: any environment that can import an ESM module
can use it without pulling in the rest of the Aje stack. It provides
OshunRpcClient — a multi-chain JSON-RPC client with retry, fallback, fan-out,
rate limiting, nonce management, gas estimation, and typed confirmation helpers.
Public exports (src/index.ts):
- Client:
OshunRpcClient,HttpTransport - Providers (
src/providers/):EthereumRpcProvider,BitcoinRpcProvider,AvalancheRpcProvider,SolanaRpcProvider - Errors:
RpcError,RpcExhaustedError,RpcMethodError,RpcNetworkError,RpcParseError,RpcQuorumError,RpcRateLimitError,RpcTimeoutError - Rate limiting:
createRateLimiter,NoopRateLimiter,RateLimiter - Retry:
DEFAULT_RETRY_POLICY,mergeRetry,withRetry - Nonce:
NonceManager,NonceLease,NonceManagerOptions - Gas:
GasEstimator,GasEstimate,EstimateOptions,EvmChain - Confirmations:
getConfirmationPolicy,getConfirmationDepth,waitForEthereumConfirmation,waitForBitcoinConfirmation,waitForSolanaConfirmation, withConfirmationLevel,ConfirmationPolicy,ConfirmationChain,ConfirmationResult,WaitOptions
Key types (src/types.ts)#
The types below govern how requests are constructed, how failures are
classified, and how retry/fallback behavior is configured. Understanding
RpcFailureKind in particular is important: it determines which failure
categories are retried versus propagated immediately.
JsonRpcRequest/JsonRpcSuccessResponse<T>/JsonRpcErrorResponse/JsonRpcErrorBody— JSON-RPC 2.0 envelopes for Ethereum, Avalanche EVM, Solana.BitcoinRpcRequestmodels Bitcoin Core's JSON-RPC 1.0 dialect.RpcFailureKind—'network' | 'rate-limit' | 'rpc-error' | 'timeout' | 'parse'. Distinguishes retry/fallback behavior.RetryPolicy—maxRetries,baseDelayMs,maxDelayMs,backoffMultiplier,jitter(±ratio),retryOn: RpcFailureKind[]. Defaults: 3 retries, 100 ms base, 10 s max, ×2, 0.25 jitter; retries network + rate-limit + timeout.RpcSendOptions— per-call overrides:timeoutMs?,retry?,fallback?,fanOut?,traceId?,signal?(AbortSignal).FallbackStrategy,FanOutStrategy— multi-endpoint walking and fan-out.EndpointConfig,OshunRpcClientOptions,RateLimit,RpcCallResult,RpcTransport,RequestHook,ResponseHook.
Wallet Specifications (@aje/wallets)#
@aje/wallets is organised as ten sub-modules, each covering a distinct aspect
of wallet management: hd-wallet, mpc, key-management,
account-abstraction, hardware-wallet, institutional, social-login,
wallet-connect, paymaster, and session-keys. The subsections below
document the key types from the three most foundational sub-modules.
HD wallets (src/hd-wallet/types.ts)#
MnemonicStrength — 128 | 160 | 192 | 224 | 256 (entropy bits).
MnemonicWordCount — 12 | 15 | 18 | 21 | 24. DerivationStandard —
'bip44' | 'bip84' | 'bip86' | 'cip1852' | 'custom'. ExtendedKeyType —
'xpub' | 'xprv' | 'ypub' | 'yprv' | 'zpub' | 'zprv'. ChainType (HD-wallet
flavour) —
'bitcoin' | 'ethereum' | 'cardano' | 'solana' | 'avalanche' | 'polygon' | 'bnb' | 'cosmos' | 'polkadot' | 'litecoin'.
Core types: Mnemonic (phrase, wordCount, language, entropy),
MnemonicGenerationOptions, MnemonicValidationResult, Seed,
PathComponent, DerivationPath, ExtendedKey, NetworkVersionBytes,
DerivedKeyPair, DerivedAddress, CoinType (chain, coinType,
curve: 'secp256k1' | 'ed25519', defaultPath, standard),
MultiChainWalletConfig, ChainAccount, MultiChainWallet,
AccountDiscoveryConfig, AccountDiscoveryScanResult, DiscoveryResult,
SerializedExtendedKey, WalletExport, and AddressUsageChecker.
MPC / threshold signatures (src/mpc/types.ts)#
MPC (Multi-Party Computation) wallet types model the distributed key generation and signing ceremonies where multiple parties must cooperate to produce a signature. The protocol proceeds through multiple communication rounds; the state machine and message types below govern the ceremony lifecycle.
MpcCurve — 'secp256k1' | 'ed25519'. MpcProtocol —
'gg18' | 'gg20' | 'cmp' | 'frost' | 'lindell17'.
MpcOperationState (state machine) —
'initialized' | 'round1' | 'round2' | 'round3' | 'completed' | 'failed' | 'aborted' | 'timed-out'.
MpcMessageType —
'commitment' | 'share' | 'decommitment' | 'challenge' | 'response' | 'proof' | 'partial-signature' | 'abort' | 'ack'.
Distributed key generation runs in three rounds: DkgRound1Data (commitments +
public coefficients + proof), DkgRound2Data (per-recipient encrypted secret
share — ChaCha20-Poly1305 ciphertext sealed with a 12-byte nonce under an
HKDF-SHA256 key derived from an X25519 shared secret), DkgRound3Data
(verification + complaints). DkgSession, DkgMessage, and DkgResult
orchestrate the ceremony. Signing produces PartialSignatures aggregated into
an AggregatedSignature (r, s, v?, signature, publicKey,
messageHash, signers); PreSignData supports faster signing. KeyShare
(partyIndex, shareData, publicKeyShare, groupPublicKey, threshold,
totalParties, curve, chainCode?, version), ShareVerificationData (with
feldmanCoefficients). KeyRefreshSession.reason ∈
'scheduled' | 'party-change' | 'compromise'. Additional types: MpcParty
(status: 'online' | 'offline' | 'removed'), ThresholdConfig,
SigningSession, SecureChannel, EncryptedMessage, MpcAuditEntry,
MpcPerformanceMetrics, BatchSignRequest, BatchSignResult.
Key management (src/key-management/types.ts)#
KeyType — 'secp256k1' | 'ed25519' | 'sr25519' | 'bls12-381'. KeyPurpose —
'signing' | 'encryption' | 'authentication' | 'derivation' | 'master'.
KeyState — 'active' | 'rotated' | 'compromised' | 'expired' | 'destroyed'.
RotationStrategy —
'time-based' | 'usage-based' | 'manual' | 'on-compromise'.
Encrypted keystore (Ethereum V3 format): KeystoreV3 with
crypto: KeystoreCrypto. KeystoreCipher is the literal 'aes-128-ctr';
KdfType is 'scrypt' | 'pbkdf2'. ScryptParams and Pbkdf2Params carry the
KDF parameters; CipherParams carries the IV. The MAC is
SHA256(derivedKey[16:32] || ciphertext). Encryption/decryption use Node's
node:crypto createCipheriv('aes-128-ctr', …). Default scrypt parameters are
defined in keystore.ts.
Other key-management types: KeyMetadata, KeyEntry, KeystoreEncryptOptions,
RotationPolicy, RotationEvent, SecretShare / ShamirConfig /
ShamirSplitResult / ShamirRecoverResult (Shamir secret sharing), Guardian
/ SocialRecoveryConfig / RecoveryRequest (social recovery), HsmInterface,
SecureEnclaveInterface, BiometricInterface, KeyAccessPolicy with
AccessRestriction (TimeRestriction | IpRestriction | RateLimitRestriction),
KeyAuditEntry, TimeLockedKeyConfig, DeadManSwitchConfig,
KeyStorageBackend.
Account Abstraction (@aje/account-abstraction)#
@aje/account-abstraction is a standalone package that goes beyond the basic
ERC-4337 support in @aje/wallets. It implements the newer and more advanced
account abstraction standards that give EOAs smart-account capabilities without
requiring an address migration. It exports five namespaces (Phase 37.26):
eip7702— EIP-7702 "set code for EOAs" delegation: lets a standard Ethereum address temporarily act as a smart contract for batching, gas sponsorship, and session keyserc7715— ERC-7715 "grant permissions": a permission grant standard that works with EIP-7702 delegationerc7579— ERC-7579 modular smart accounts: composable execution, validation, hook, and fallback modules assembled as building blockserc6900— ERC-6900 modular accounts (Alchemy): plugins that define both validation and execution logic for more powerful compositionsadvancedAA— advanced account-abstraction infrastructure
Settlement Escrow (@aje/settlement-escrow)#
@aje/settlement-escrow (Phase 179.7.2.4) is the integration point between the
Concordia domain's clause lifecycle and Aje's blockchain execution layer. It
bridges a validated Concordia escrow_release clause to a chain-ready escrow
deployment plan. The entire implementation lives in src/escrow-adapter.ts,
which exports Zod schemas, the inferred TypeScript types, and two functions. It
depends on @concordia/contracts and zod; notably it does not depend on
@aje/core, keeping it lightweight and independently deployable.
The schemas below use Zod, which provides both runtime validation and TypeScript
type inference. Each inferred type is derived via z.infer<typeof Schema>.
EscrowChainSchema — z.enum#
'ethereum' | 'polygon' | 'arbitrum' | 'optimism' | 'base' | 'starknet' | 'aptos' | 'sui' | 'solana' | 'near' | 'cosmos' | 'bitcoin' | 'tenant_private_chain'.
Inferred type EscrowChain.
OracleSourceSchema — z.enum#
'mediator_attestation' | 'dual_party_attestation' | 'oracle_chainlink' | 'oracle_uma' | 'court_order' | 'kleros_arbitration' | 'tenant_admin'.
Inferred type OracleSource.
EscrowMilestonePlanSchema#
| Field | Type / rule |
|---|---|
id |
non-empty string |
label |
non-empty string |
releaseFraction |
number in [0, 1] |
dueAt |
optional ISO datetime with offset |
oracleSource |
OracleSource |
releaseAmountMinorUnits |
decimal-digit string (/^\d+$/) — bigint amount in minor units |
EscrowDeploymentPlanSchema#
| Field | Type / rule |
|---|---|
caseId |
non-empty string |
clauseId |
non-empty string |
chain |
EscrowChain |
tokenRef |
non-empty string |
tokenDecimals |
integer in [0, 36] |
principalAmount |
decimal-digit string (/^\d+$/) |
escrowContractRef |
non-empty string — deployment ref that will hold the escrow |
milestones |
readonly array of EscrowMilestonePlan, min length 1 |
arbitrationBackstop |
'kleros' | 'uma_optimistic' | 'court_order' | 'platform_arbitrator' | 'tenant_reviewer' | 'none' |
challengeWindowSeconds |
optional non-negative integer |
agreementHash |
optional 0x-prefixed 64-hex-char string — clause-text hash anchored on-chain at deposit |
Validation rules (superRefine):
- Milestone
releaseFractionvalues must sum to 1 (tolerance 1e-6). - The sum of milestone
releaseAmountMinorUnitsmust exactly equalprincipalAmount.
Functions#
planDeployment(args)— builds anEscrowDeploymentPlanfrom a Concordiaescrow_releasepayload. It allocates each milestone'sreleaseAmountMinorUnitsfromreleaseFractionusing integer math at a 1,000,000 scale; the final milestone absorbs any rounding dust so totals match exactly. The result is validated throughEscrowDeploymentPlanSchema.nextMilestoneAfter(plan, cutoff)— returns the next unreleased milestone in due-date order aftercutoff, ornull. Milestones withoutdueAtare excluded from the ordering.
Persistence (@aje/database)#
@aje/database is a DDL-and-query-builder library, not a Drizzle-ORM
runtime. The distinction matters: it does not introduce an ORM abstraction layer
or a connection pool of its own. Instead, it emits PostgreSQL DDL and
parameterized queries via @oshun/database helpers (sql, sqlRaw,
ParameterizedQuery). Each table has a corresponding create<Name>Table()
function that returns a ParameterizedQuery object containing an idempotent
CREATE TABLE IF NOT EXISTS statement. The package exports five namespaces,
each grouping related tables by domain concern: coreSchema, defiSchema,
walletSchema, indexer, maintenance.
Tables by namespace#
The table below lists every table in each namespace. coreSchema covers the raw
blockchain data (chains, blocks, transactions, logs, tokens); walletSchema
covers user-facing wallet and identity records; defiSchema covers DeFi
protocol positions and portfolio analytics; indexer covers the on-chain event
ingestion pipeline; and maintenance covers operational and compliance records.
| Namespace | Tables |
|---|---|
coreSchema |
chain_configs, network_status, rpc_endpoints, block_explorers, reorg_events, indexer_checkpoints, block_gaps, blocks, transactions, transaction_receipts, event_logs, contracts, address_labels, tokens, nfts, balances, allowances, gas_price_history |
walletSchema |
wallets, aa_accounts, session_keys, multisig_configs, did_documents, verifiable_credentials, ens_cache, wallet_address_labels, contacts, wallet_transactions, notifications, wallet_preferences, audit_logs, kyc_records, compliance_rules |
defiSchema |
dex_swaps, dex_volumes, dex_fees, liquidity_pools, liquidity_positions, impermanent_loss, lending_positions, liquidation_events, borrowing_rates, yield_sources, reward_claims, apy_history, protocol_tvl, portfolio_pnl, portfolio_snapshots |
indexer |
price_feeds, contract_events_index, token_transfers, subgraph_entities, api_keys, websocket_subscriptions, indexer_jobs, ingestion_logs, indexer_health, indexer_alerts |
maintenance |
blockchain_migrations, migration_locks, backup_records, retention_policies, gdpr_requests, compliance_audit_log |
Representative table definitions#
The two DDL samples below illustrate the table design conventions: UUID primary
keys, foreign key constraints with ON DELETE CASCADE, CHECK constraints for
enum-like columns, TIMESTAMPTZ timestamps, and NUMERIC(78) for 256-bit
on-chain integers. All CREATE TABLE statements are IF NOT EXISTS and are
therefore safe to re-run on startup.
chain_configs:
CREATE TABLE IF NOT EXISTS chain_configs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
chain_id INTEGER NOT NULL,
name VARCHAR(128) NOT NULL,
short_name VARCHAR(32),
network_type VARCHAR(16) NOT NULL CHECK (network_type IN ('mainnet','testnet','devnet','local')),
consensus_type VARCHAR(8) NOT NULL CHECK (consensus_type IN ('pow','pos','dpos','poa','pbft')),
native_currency_name VARCHAR(64) NOT NULL,
native_currency_symbol VARCHAR(16) NOT NULL,
native_currency_decimals INTEGER NOT NULL DEFAULT 18,
is_evm BOOLEAN NOT NULL DEFAULT false,
average_block_time_ms INTEGER,
required_confirmations INTEGER NOT NULL DEFAULT 12,
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (chain_id, network_type)
);
transactions carries chain_config_id and block_id foreign keys, tx_hash,
tx_index, tx_type, from_address, to_address, value, nonce,
gas_limit, gas_price, max_fee_per_gas, max_priority_fee_per_gas,
input_data, a status check constraint
('pending','submitted','confirmed','failed','dropped','replaced'),
block_number, block_hash, timestamp, and is unique on
(chain_config_id, tx_hash). transaction_receipts has a one-to-one
transaction_id FK and a status check ('success','reverted'). High-value
numerics use NUMERIC(78) to hold 256-bit on-chain integers.
wallets:
CREATE TABLE IF NOT EXISTS wallets (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
chain_config_id UUID NOT NULL REFERENCES chain_configs(id) ON DELETE CASCADE,
address VARCHAR(128) NOT NULL,
wallet_type VARCHAR(16) NOT NULL CHECK (wallet_type IN ('eoa','smart_account','multisig','hardware','mpc')),
name VARCHAR(128),
derivation_path VARCHAR(64),
public_key VARCHAR(256),
is_imported BOOLEAN NOT NULL DEFAULT false,
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (chain_config_id, address)
);
aa_accounts records ERC-4337 accounts (factory_address,
implementation_address, entry_point_address, owner_address, salt,
is_deployed, deploy_tx_hash). session_keys records scoped keys
(permissions JSONB, valid_after, valid_until, spending_limit,
spending_used, is_revoked).
ORM-schema generator (maintenance/orm-integration.ts)#
The maintenance namespace contains a code generator that converts an internal
OrmSchemaDefinition into Prisma or Drizzle schema source. It exposes
sqlTypeToPrisma, sqlTypeToDrizzle, generateDrizzleTable,
generateDrizzleSchema, and Prisma equivalents. This is a developer tool that
emits schema strings; it is not how @aje/database itself talks to PostgreSQL.
V2 Game-Domain Integrations#
Two services in the V2 game project consume Aje primitives behind a
gameplay-safety envelope. Both exist on disk under V2/services/. The safety
envelope is important: blockchain features for games carry regulatory
uncertainty in many jurisdictions, so both services require explicit opt-in from
the user, check a platform cert-ban table before surfacing any blockchain UI,
and are blocked at binary cook time by a Python check script when the relevant
platforms are not cleared.
V2 Web3 Cosmetic Ownership Contract — @v2/aje-web3-cosmetic-ownership#
Consumes @aje/identity and @aje/nft for wallet-bound cosmetic ownership. Aje
owns the wallet/DID and NFT primitives; V2 owns the safety boundary:
- The
V2_AJE_WEB3_COSMETIC_OWNERSHIP_WARNINGconstant must be accepted before any wallet-bound cosmetic is surfaced; the service supplies it aswarningText.evaluateV2AjeWeb3CosmeticOwnershipPolicyreturnsblocked-warning-not-accepteduntil that exact string is acknowledged, andblocked-missing-opt-inuntiloptIn.grantedis set. - The surface only verifies — never mints — ownership:
credentials.verifyCredential(@aje/identity) proves the wallet/DID binding anderc721.getTokenOwnership(@aje/nft) confirms on-chain custody of the cosmetic token. It carriesmayInfluenceRollback: false, so a wallet's cosmetic display can never alter deterministic match simulation. V2/legal/platform-cert-bans.jsonis the legal source of truth for platform, region, age-rating, banned surfaces, and effective-date windows. The sharedV2/ue/Tools/check-platform-cert-bans.pygate validates that table and thePlatformCookAjeReachability.jsonmanifest, returningblocked-platform-cert-bannedfor theon_chain_in_game_items/cosmetic_nft_ownership/web3_cosmetic_ownershipsurfaces wherever a publisher-legal entry bans them.V2/ue/Tools/check-v2-aje-web3-cosmetic-ownership.pyblocks cooked binaries when@aje/identityor@aje/nftis reachable on a platform where on-chain in-game items are banned or not explicitly cleared.
V2 Fan-Token Faction Governance Contract — @v2/aje-faction-governance#
Consumes @aje/governance for optional fan-token-gated faction governance:
- The
V2_AJE_FACTION_GOVERNANCE_WARNINGconstant must be accepted before any fan-token faction vote opens.evaluateV2AjeFactionGovernancePolicyenforcesrequiresExplicitOptIn: trueand only then composes a Snapshot vote viasnapshot.createERC20Strategy/snapshot.buildSpace/snapshot.buildProposal, so an external ERC-20 fan-token balance gates a faction ballot rather than in-game state. The decision surface isoffRollback: true/mayInfluenceRollback: false. - The
fan_token_gated_gameplaysurface inV2/legal/platform-cert-bans.jsongoverns where this is allowed. The sharedV2/ue/Tools/check-platform-cert-bans.pygate (which lists@aje/governanceinREQUIRED_AJE_SURFACE_PACKAGES) refuses any cook that reaches the governance package on a platform that has not explicitly clearedfan_token_gated_gameplay, andV2/ue/Tools/check-v2-aje-faction-governance.pyenforces the per-binary wiring.
Configuration#
Aje deliberately avoids a monolithic global configuration object. Each package
is independently configured through the typed objects it defines, and consumers
pass those objects at construction time. This makes each package usable in
isolation without having to reason about the full domain config. Representative
configuration types include ChainProviderConfig, OshunRpcClientOptions,
RetryPolicy, FallbackConfig, MultiChainWalletConfig, and
KeystoreEncryptOptions. There is no single global AjeConfig type and no
central config file in the domain.
Cross-Domain Integration Points#
Aje is a foundational domain: it depends outward on a small set of shared
workspace packages, and it is consumed inward by two specialised surfaces in the
V2 game project. There is no event-bus integration in either direction — no Aje
package imports @oshun/event-bus, and Aje publishes no Kafka or Redis-Stream
messages.
| Counterpart | Direction | Mechanism |
|---|---|---|
@oshun/crypto |
aje → shared | Workspace crypto package; runtime dependency of most Aje packages |
@oshun/types |
aje → shared | Optional peer dependency of @aje/core |
@oshun/database |
aje → shared | Peer of @aje/database; provides sql/sqlRaw/ParameterizedQuery |
@concordia/contracts |
aje → concordia | Runtime dependency of @aje/settlement-escrow |
@aje/identity, @aje/nft |
V2 → aje | Consumed by @v2/aje-web3-cosmetic-ownership |
@aje/governance |
V2 → aje | Consumed by @v2/aje-faction-governance |
Acceptance Criteria#
- All 31
@aje/*packages build and pass their Vitest suites (each package ships*.spec.tsfiles alongside its modules). @aje/coreexposes addresses, transactions, blocks, BigNumber, crypto, ABI, events, Merkle trees, network config, and errors through one barrel export.- Cryptography uses only
@noble,@scure,@oshun/crypto, and Node's built-innode:crypto(AES). No custom curve or hash code exists. @aje/settlement-escrowrejects any deployment plan whose milestone fractions do not sum to 1 or whose milestone amounts do not sum to the principal.@aje/databaseDDL functions produce idempotentCREATE TABLE IF NOT EXISTSstatements with the documented columns, check constraints, and uniqueness constraints.@aje/rpcretries only the failure kinds inRetryPolicy.retryOnand walks endpoints per the configuredFallbackStrategy/FanOutStrategy.
Grounding#
Every type, enum, schema, table, and function above was read directly from
libs/aje/* source: @aje/core (addresses/, transactions/, blocks/,
bignum/, network/, abi/, events/, errors/, crypto/),
@aje/chains/abstraction, @aje/rpc, @aje/wallets (hd-wallet/, mpc/,
key-management/), @aje/account-abstraction, @aje/database, and
@aje/settlement-escrow. The library inventory comes from each package's
package.json and src/index.ts. The V2 integration is grounded in
apps/v2/aje-* and V2/ue/Tools/check-v2-aje-*.py. Phase 37 is the Aje domain
backlog in TODOS.md; @aje/settlement-escrow is Phase 179.7.2.4 and is listed
as Implemented in DOMAINS/concordia/specifications.md.