@skate-org/amm-bindings
v1.0.0
Published
TypeScript bindings (ABI + Selectors) for Skate AMM contracts
Readme
@skate-org/amm-bindings
TypeScript bindings for Skate AMM contracts - providing type-safe access to ABIs and function selectors.
Features
- ✅ Type-safe ABIs - All contract ABIs exported as TypeScript constants with proper typing
- ✅ Function Selectors - Enums for all contract function selectors
- ✅ Reverse Mapping - Look up method signatures from bytes4 selectors
- ✅ Global Selector Directory - Unified lookup across all contracts with smart inheritance handling
- ✅ Dual Build - ESM and CJS support via tsup
- ✅ Auto-generated - Automatically generated from contract artifacts
- ✅ Tree-shakeable - Import only what you need
- ✅ Source Maps - Full source map support for debugging
Installation
npm install @skate-org/amm-bindings
# or
yarn add @skate-org/amm-bindings
# or
pnpm add @skate-org/amm-bindingsContract Architecture
Skate AMM is a cross-chain AMM protocol built on intent-based architecture. The system is organized into four main layers:
1. AMM Kernel (Skate Chain - Settlement Layer)
The canonical state and settlement layer for the AMM, running on the Skate chain:
KernelManager - Central AMM management contract
- Manages pool lifecycle (creation, upgrades)
- Issues ERC721 NFTs representing liquidity positions
- Coordinates liquidity operations (mint, burn, increase/decrease)
- Executes swaps and manages protocol fees
KernelPool - Individual AMM pool implementation (Uniswap V3-based)
- Implements concentrated liquidity with tick-based positions
- Handles swap calculations and execution
- Tracks pool state, fees, and oracle data
- Uses UUPS upgradeable pattern
2. AMM Periphery (Execution Chains - User-Facing Layer)
User-facing contracts deployed on execution chains (Ethereum, Arbitrum, etc.):
PeripheryManager - Manages periphery pools on execution chains
- Deploys and tracks periphery pools
- Manages pool creator permissions and fee settings
- Links periphery pools to their kernel counterparts
PeripheryPool - User-facing pool contract
- Accepts user deposits and withdrawals
- Processes swap requests
- Normalizes token amounts across different decimals
- Creates actions that are bridged to the kernel
- Settles operations after kernel execution
3. Skate Kernel (Cross-Chain Infrastructure - Settlement)
Cross-chain messaging infrastructure on the Skate chain:
SkateApp - Base application contract for the kernel chain
- Processes intents received from periphery chains
- Manages periphery contract mappings
- Integrates with MessageBox for task management
MessageBox - Intent and task orchestration system
- Receives and validates user intents with signatures
- Emits events for off-chain relayers
- Tracks task execution status with nonce management
AccountRegistry - Multi-chain account management
- Binds wallets across different VM types (EVM, non-EVM)
- Manages cross-chain identity
4. Skate Periphery (Cross-Chain Infrastructure - Execution)
Cross-chain messaging infrastructure on execution chains:
SkateAppPeriphery - Base application contract for periphery chains
- Manages gateway connections
- Provides gateway-only access control
SkateGateway - Task execution gateway
- Executes tasks from the kernel chain
- Validates task signatures from trusted signers
- Routes calls to periphery applications
ActionBox - Action creation and tracking
- Emits ActionCreated events for off-chain services
- Converts user actions into intents
Cross-Chain Flow
User → PeripheryPool → ActionBox (emit event)
↓
Off-chain Relayer
↓
MessageBox → SkateApp → KernelManager → KernelPool (execute)
↓
Task Created
↓
Off-chain Executor
↓
SkateGateway → PeripheryPool (settle)Usage
What are ABIs?
ABIs (Application Binary Interfaces) define how to interact with smart contracts. They specify:
- Function names and parameters
- Event signatures
- Return types
This package exports type-safe ABIs for all Skate AMM contracts, compatible with libraries like viem, ethers, and web3.js.
Importing ABIs
import { KernelManagerABI, PeripheryPoolABI } from '@skate-org/amm-bindings';
// Use with viem
import { createPublicClient, http } from 'viem';
const client = createPublicClient({
transport: http(),
});
const data = await client.readContract({
address: '0x...',
abi: KernelManagerABI,
functionName: 'getPool',
args: [token0, token1, fee],
});What are Function Selectors?
Function selectors are the first 4 bytes of a function's keccak256 hash, used to identify which function to call in a smart contract. This package provides:
- Enums - Type-safe selector constants
- Forward mapping - Function signature → selector
- Reverse mapping - Selector → function signature
Useful for:
- Decoding transaction calldata
- Building custom transaction encoders
- Debugging smart contract interactions
- Creating minimal proxies or routers
Importing Selectors
import {
KernelManagerSelectors,
KernelManagerSelectorsMap,
KernelManagerSelectorsReverse
} from '@skate-org/amm-bindings';
// Use enum values - type-safe and autocomplete-friendly
const selector = KernelManagerSelectors.createPool;
console.log(selector); // '0xda7df29f'
// Forward lookup: function signature → selector
const sig = 'createPool(address,address,uint24)';
const selector2 = KernelManagerSelectorsMap[sig];
console.log(selector2); // '0xda7df29f'
// Reverse lookup: selector → function signature
const signature = KernelManagerSelectorsReverse['0xda7df29f'];
console.log(signature); // 'createPool(address,address,uint24)'
// Example: Decode transaction calldata
const txData = '0xda7df29f000000000000000000000000...';
const functionSig = KernelManagerSelectorsReverse[txData.slice(0, 10)];
console.log(`Calling function: ${functionSig}`);Global Selector Lookup
For decoding arbitrary transaction calldata, use the global reverse mapping:
import {
GlobalSelectorsReverse,
GlobalSelectorsReverseAll,
lookupSelector,
lookupSelectorAll
} from '@skate-org/amm-bindings';
// Quick lookup - returns first match (prefers concrete implementations over interfaces)
const signature1 = lookupSelector('0xda7df29f');
console.log(signature1); // 'createPool(address,address,uint24)'
// Also works without 0x prefix
const signature2 = lookupSelector('da7df29f');
console.log(signature2); // 'createPool(address,address,uint24)'
// Get all contracts that define a selector (useful for inherited methods)
const allMatches = lookupSelectorAll('0x01ffc9a7');
console.log(allMatches);
// [
// { contract: 'KernelManager', signature: 'supportsInterface(bytes4)' },
// { contract: 'KernelManagerStorage', signature: 'supportsInterface(bytes4)' },
// { contract: 'IKernelManager', signature: 'supportsInterface(bytes4)' }
// ]
// Direct access to mappings
const sig = GlobalSelectorsReverse['0xda7df29f'];
const allSigs = GlobalSelectorsReverseAll['0x01ffc9a7'];Selector Resolution Strategy:
- The global mapping contains 246+ unique selectors from all contracts
- When a selector appears in multiple contracts (due to inheritance),
GlobalSelectorsReverseprefers:- Concrete implementations over interfaces
- The first occurrence found in the contract tree
- Use
GlobalSelectorsReverseAllto see all contracts that define a specific selector
Importing Everything
import { ABIs, Selectors } from '@skate-org/amm-bindings';
// Access all ABIs
const kernelManagerABI = ABIs.KernelManager;
const peripheryPoolABI = ABIs.PeripheryPool;
// Access all selectors
const kernelSelectors = Selectors.KernelManager;
const peripherySelectors = Selectors.PeripheryPool;Available Contracts
All contracts are exported with three naming conventions:
{ContractName}ABI- The contract ABI{ContractName}Selectors- Function selectors enum{ContractName}SelectorsMap- Forward mapping (signature → selector){ContractName}SelectorsReverse- Reverse mapping (selector → signature)
AMM Contracts
Kernel Contracts (Skate Chain)
Core AMM logic and settlement layer:
| Contract | Purpose | Key Functions |
|----------|---------|---------------|
| KernelManager | Central AMM management | createPool, mint, burn, swap, collect |
| KernelPool | Individual pool implementation | Uniswap V3 pool interface + upgrades |
| KernelEventEmitter | Centralized event emission | Pool creation, swap, mint, burn events |
| KernelManagerStorage | Storage layout | State variables for manager |
Periphery Contracts (Execution Chains)
User-facing contracts on multiple chains:
| Contract | Purpose | Key Functions |
|----------|---------|---------------|
| PeripheryManager | Periphery pool management | createPool, pool tracking, permissions |
| PeripheryPool | User interaction layer | mint, burn, swap, settle operations |
| PeripheryEventEmitter | Event emission | Action and settlement events |
AMM Interfaces
Type-safe interfaces for all AMM contracts:
IKernelManager- Kernel manager interfaceIKernelPool- Pool operations interfaceIPeripheryManager- Periphery manager interfaceIPeripheryPool- Periphery pool interfaceIERC20Minimal- Minimal ERC20 interface- Uniswap V3 interfaces:
IUniswapV3Pool*(Actions, State, Events, etc.)
Skate Infrastructure Contracts
Kernel Contracts (Skate Chain)
Cross-chain messaging infrastructure on settlement layer:
| Contract | Purpose | Key Functions |
|----------|---------|---------------|
| SkateApp | Base kernel application | processIntent, periphery management |
| MessageBox | Intent/task orchestration | submitIntent, task tracking |
| AccountRegistry | Multi-chain accounts | bindAccount, VM type management |
| AccountStorage | Account storage | Storage for account bindings |
Periphery Contracts (Execution Chains)
Cross-chain messaging infrastructure on execution chains:
| Contract | Purpose | Key Functions |
|----------|---------|---------------|
| SkateAppPeriphery | Base periphery application | Gateway connection, access control |
| SkateGateway | Task execution gateway | executeTask, signature validation |
| ActionBox | Action tracking | Action creation and emission |
Common Contracts
Shared utilities across all chains:
| Contract | Purpose | Key Functions |
|----------|---------|---------------|
| ExecutorRegistry | Executor permissions | addExecutor, removeExecutor |
| Multicall | Batch operations | multicall for multiple calls |
Interface Naming Convention
Interfaces are prefixed with I and follow the same export pattern:
import { IKernelManagerABI, IPeripheryPoolABI } from '@skate-org/amm-bindings';Practical Examples
Example 1: Reading Pool State with viem
import { createPublicClient, http } from 'viem';
import { arbitrum } from 'viem/chains';
import { PeripheryPoolABI } from '@skate-org/amm-bindings';
const client = createPublicClient({
chain: arbitrum,
transport: http(),
});
// Read pool token addresses
const token0 = await client.readContract({
address: '0x...',
abi: PeripheryPoolABI,
functionName: 'token0',
});
// Read pool state
const [sqrtPriceX96, tick, observationIndex] = await client.readContract({
address: '0x...',
abi: PeripheryPoolABI,
functionName: 'slot0',
});
console.log(`Current tick: ${tick}`);Example 2: Creating a Pool on Periphery
import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { PeripheryManagerABI } from '@skate-org/amm-bindings';
const account = privateKeyToAccount('0x...');
const client = createWalletClient({
account,
chain: arbitrum,
transport: http(),
});
// Create a new pool
const hash = await client.writeContract({
address: PERIPHERY_MANAGER_ADDRESS,
abi: PeripheryManagerABI,
functionName: 'createPool',
args: [
'0x...', // token0
'0x...', // token1
3000, // fee (0.3%)
],
});
console.log(`Pool creation tx: ${hash}`);Example 3: Decoding Transaction Calldata
import { decodeFunctionData } from 'viem';
import {
KernelManagerABI,
KernelManagerSelectors,
lookupSelector
} from '@skate-org/amm-bindings';
// Transaction calldata from a blockchain explorer
const txData = '0xda7df29f0000000000000000000000001234...';
// Method 1: Quick lookup
const functionSig = lookupSelector(txData.slice(0, 10));
console.log(`Function: ${functionSig}`);
// Method 2: Full decode with viem
const decoded = decodeFunctionData({
abi: KernelManagerABI,
data: txData,
});
console.log(`Function: ${decoded.functionName}`);
console.log(`Args:`, decoded.args);Example 4: Listening to Events
import { createPublicClient, http, parseAbiItem } from 'viem';
import { PeripheryPoolABI } from '@skate-org/amm-bindings';
const client = createPublicClient({
chain: arbitrum,
transport: http(),
});
// Watch for swap events
const unwatch = client.watchContractEvent({
address: PERIPHERY_POOL_ADDRESS,
abi: PeripheryPoolABI,
eventName: 'Swap',
onLogs: (logs) => {
logs.forEach((log) => {
console.log('Swap event:', {
sender: log.args.sender,
recipient: log.args.recipient,
amount0: log.args.amount0,
amount1: log.args.amount1,
sqrtPriceX96: log.args.sqrtPriceX96,
tick: log.args.tick,
});
});
},
});
// Stop watching after some time
setTimeout(() => unwatch(), 60000);Example 5: Building a Multi-chain Pool Monitor
import { createPublicClient, http } from 'viem';
import { arbitrum, optimism, base } from 'viem/chains';
import { PeripheryPoolABI, PeripheryPoolSelectors } from '@skate-org/amm-bindings';
const chains = [arbitrum, optimism, base];
const poolAddress = '0x...'; // Same pool on different chains
// Monitor pool state across multiple chains
const poolStates = await Promise.all(
chains.map(async (chain) => {
const client = createPublicClient({
chain,
transport: http(),
});
const [token0, token1, fee, slot0] = await Promise.all([
client.readContract({
address: poolAddress,
abi: PeripheryPoolABI,
functionName: 'token0',
}),
client.readContract({
address: poolAddress,
abi: PeripheryPoolABI,
functionName: 'token1',
}),
client.readContract({
address: poolAddress,
abi: PeripheryPoolABI,
functionName: 'fee',
}),
client.readContract({
address: poolAddress,
abi: PeripheryPoolABI,
functionName: 'slot0',
}),
]);
return {
chain: chain.name,
token0,
token1,
fee,
tick: slot0[1],
};
})
);
console.log('Pool states across chains:', poolStates);Example 6: Type-Safe Event Filtering
import { PeripheryPoolABI } from '@skate-org/amm-bindings';
import { parseAbiItem } from 'viem';
// Extract event signatures with full type safety
const swapEvent = PeripheryPoolABI.find(
(item) => item.type === 'event' && item.name === 'Swap'
);
if (swapEvent && swapEvent.type === 'event') {
console.log('Swap event inputs:', swapEvent.inputs);
// TypeScript knows the exact shape of swapEvent.inputs
}
// Get logs for specific events
const logs = await client.getLogs({
address: PERIPHERY_POOL_ADDRESS,
event: parseAbiItem('event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick)'),
fromBlock: 'earliest',
toBlock: 'latest',
});Development
Regenerate Bindings
# From the package directory (packages/ts-binding)
npm run generate
# or
make generate
# From the root repository
make gen-all
cd packages/ts-binding && make generateBuild
npm run build
# or
make buildTest
# Run all tests
npm test
# or
make test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverage
# or
make test-coverageClean
npm run clean
# or
make cleanAvailable Make Commands
Run make help to see all available commands:
make install- Install dependenciesmake generate- Generate TypeScript from ABIs/selectorsmake build- Build the packagemake clean- Clean generated filesmake check- Verify generated files are up-to-datemake all- Clean, install, generate, and build
Package Structure
Distribution Files
dist/
├── index.js # ESM build
├── index.cjs # CommonJS build
├── index.d.ts # TypeScript declarations (ESM)
├── index.d.cts # TypeScript declarations (CJS)
└── *.map # Source mapsSource Files (Generated)
src/generated/
├── abis/
│ ├── amm/
│ │ ├── kernel/ # Kernel contract ABIs
│ │ │ ├── KernelManager.ts
│ │ │ ├── KernelPool.ts
│ │ │ ├── KernelEventEmitter.ts
│ │ │ └── interfaces/ # Interface ABIs
│ │ └── periphery/ # Periphery contract ABIs
│ │ ├── PeripheryManager.ts
│ │ ├── PeripheryPool.ts
│ │ └── interfaces/
│ └── skate/
│ ├── common/ # Common utilities
│ │ ├── ExecutorRegistry.ts
│ │ └── Multicall.ts
│ ├── kernel/ # Skate kernel infrastructure
│ │ ├── SkateApp.ts
│ │ ├── MessageBox.ts
│ │ ├── AccountRegistry.ts
│ │ └── interfaces/
│ └── periphery/ # Skate periphery infrastructure
│ ├── SkateAppPeriphery.ts
│ ├── SkateGateway.ts
│ ├── ActionBox.ts
│ └── interfaces/
│
├── selectors/ # Same structure as abis/
│ ├── amm/
│ │ ├── kernel/
│ │ └── periphery/
│ └── skate/
│ ├── common/
│ ├── kernel/
│ └── periphery/
│
└── index.ts # Main export file
scripts/
└── generate.mjs # Generation scriptHow It Works
- Generation: The
generate.mjsscript reads contract artifacts (ABIs) from the compiled contracts and generates TypeScript files - ABIs: Each contract gets an ABI file exported as a typed constant with
as constassertion - Selectors: For each contract, generates:
- Enum of function selectors
- Forward map (signature → selector)
- Reverse map (selector → signature)
- Global Maps: Creates unified selector lookup across all contracts
- Build:
tsupbundles everything into ESM and CJS formats with type declarations
TypeScript Support
This package is built with TypeScript and includes full type definitions. All ABIs are typed with as const assertions, providing maximum type safety and enabling powerful TypeScript features.
Type Inference
import { KernelManagerABI } from '@skate-org/amm-bindings';
// The ABI type is inferred from the const assertion
type KernelManagerABIType = typeof KernelManagerABI;
// viem automatically infers function names and parameters
import { createPublicClient, http } from 'viem';
const client = createPublicClient({ transport: http() });
// TypeScript knows all available functions and their signatures
const result = await client.readContract({
address: '0x...',
abi: KernelManagerABI,
functionName: 'getPool', // ✅ Autocomplete works!
args: [token0, token1, fee], // ✅ Type-checked!
});Selector Type Safety
import { KernelManagerSelectors } from '@skate-org/amm-bindings';
// Selectors are typed enums - no magic strings!
const selector: string = KernelManagerSelectors.createPool;
// TypeScript prevents typos
// const wrong = KernelManagerSelectors.creatPool; // ❌ Compile errorBenefits of Type Safety
- Autocomplete: IDEs suggest available functions and events
- Compile-time validation: Catch errors before runtime
- Refactoring support: Renaming works across your codebase
- Documentation: Inline types serve as documentation
- Fewer bugs: Type mismatches caught during development
License
MIT
Publishing
Prerequisites
- NPM Account: You need an npm account with publish access to
@skate-org - Authentication: Login to npm (only needed once per machine)
npm loginPublishing Workflow
# 1. Update version in package.json
# Follow semantic versioning: major.minor.patch
# 2. Generate and build
make build
# 3. Test the package locally (dry run)
npm run publish:dry
# or
make publish-dry
# 4. Publish to npm
npm run publish:release
# or
make publishAutomated Publishing (CI/CD)
For CI/CD pipelines, set the NPM_TOKEN environment variable:
# GitHub Actions example
- name: Publish to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}Contributing
This package is auto-generated from the contract artifacts. To update:
- Update the contracts in the main repository
- Run
make gen-allto regenerate ABIs and selectors - Run
npm run buildin this package to rebuild bindings - Commit the generated files
