
Product
Introducing Webhook Events for Alert Changes
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.
@1inch/swap-vm-sdk
Advanced tools
A TypeScript SDK for encoding, decoding, and interacting with the 1inch Swap VM Protocol smart contract. This SDK provides utilities for building transactions, parsing events, and managing virtual machine instructions for the Swap VM Protocol's core operations.
The Swap VM Protocol is a lightweight virtual machine designed for efficient and flexible token swapping on-chain. This SDK simplifies integration by providing:
quote, swap, and hash operationsFor detailed protocol documentation, see the Swap VM Protocol Documentation.
pnpm add @1inch/swap-vm-sdk
import {
AQUA_SWAP_VM_CONTRACT_ADDRESSES,
Address,
NetworkEnum,
Order,
MakerTraits,
AquaAMMStrategy
} from '@1inch/swap-vm-sdk'
import { AquaProtocolContract, AQUA_CONTRACT_ADDRESSES } from '@1inch/aqua-sdk'
const chainId = NetworkEnum.ETHEREUM
const aqua = new AquaProtocolContract(AQUA_CONTRACT_ADDRESSES[chainId])
const swapVMAddress = AQUA_SWAP_VM_CONTRACT_ADDRESSES[chainId]
const maker = '0xmaker_address'
const USDC = new Address('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48')
const WETH = new Address('0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2')
const program = AquaAMMStrategy.new({
tokenA: USDC,
tokenB: WETH
}).build()
const order = Order.new({
maker: new Address(maker),
program,
traits: MakerTraits.default()
})
const tx = aqua.ship({
app: new Address(swapVMAddress),
strategy: order.encode(),
amountsAndTokens: [
{
amount: 10000n * 10n ** 6n,
token: USDC
},
{
amount: 5n * 10n ** 18n,
token: WETH
}
]
})
await makerWallet.send(tx)
import {
Order,
HexString,
TakerTraits,
Address,
AQUA_SWAP_VM_CONTRACT_ADDRESSES,
NetworkEnum,
SwapVMContract,
ABI
} from '@1inch/swap-vm-sdk'
import { decodeFunctionResult } from 'viem'
const chainId = NetworkEnum.ETHEREUM
const swapVM = new SwapVMContract(AQUA_SWAP_VM_CONTRACT_ADDRESSES[chainId])
const USDC = new Address('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48')
const WETH = new Address('0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2')
const encodedOrder = '0x...' // fetched from ship event or from api
const order = Order.parse(new HexString(encodedOrder))
const srcAmount = 100n * 10n ** 6n
const swapParams = {
order,
amount: srcAmount,
takerTraits: TakerTraits.default(),
tokenIn: USDC,
tokenOut: WETH
}
// Simulate the call to get the dstAmount
const simulateResult = await taker.call(swapVM.quote(swapParams))
const [_, dstAmount] = decodeFunctionResult({
abi: ABI.SWAP_VM_ABI,
functionName: 'quote',
data: simulateResult.data!
})
console.log('dstAmount', dstAmount)
// Swap
const swapTx = swapVM.swap(swapParams)
await taker.send(swapTx)
Get a quote for a swap.
const quoteTx = swapVm.quote({
order: Order.parse('0x...'),
tokenIn: new Address('0x...'),
tokenOut: new Address('0x...'),
amount: 1000000000000000000n,
takerTraits: TakerTraits.default(),
})
Parameters:
order - The maker's order (fetched from ship event or from api)tokenIn - The input token addresstokenOut - The output token addressamount - The input amount to quotetakerTraits - Taker-specific traits configurationReturns: CallInfo object with encoded transaction data
Execute a swap transaction.
const swapTx = swapVm.swap({
order: Order.parse('0x...'),
tokenIn: new Address('0x...'),
tokenOut: new Address('0x...'),
amount: 1000000000000000000n,
takerTraits: TakerTraits.default(),
})
Parameters:
quoteReturns: CallInfo object with encoded transaction data
Calculate the hash of an order (view).
const order = new Order({
maker: new Address('0x...'),
traits: MakerTraits.default(),
program: new HexString('0x...'),
})
const hashOrderTx = swapVm.hashOrder(order)
Parameters:
order - The order to hashReturns: CallInfo object with encoded transaction data for the hash order function
Emitted when a swap is executed.
import { SwappedEvent } from '@1inch/swap-vm-sdk'
const log = { data: '0x...', topics: ['0x...'] }
const event = SwappedEvent.fromLog(log)
console.log(event.orderHash) // HexString
console.log(event.maker) // Address
console.log(event.taker) // Address
console.log(event.tokenIn) // Address
console.log(event.tokenOut) // Address
console.log(event.amountIn) // bigint
console.log(event.amountOut) // bigint
The Swap VM uses a comprehensive instruction system for building swap programs.
🔎 Instruction coverage vs. deployment
_allInstructions in src/swap-vm/instructions/index.ts) and can safely encode/decode every core opcode defined by the protocol.AquaSwapVMRouter contracts support only the Aqua subset of these instructions (see aquaInstructions in the same file).aquaInstructions will not be executable on current Aqua deployments, even though encoding/decoding will succeed.Fusaka Ethereum hardfork, a full SwapVM deployment is planned; at that point, programs using the complete _allInstructions set will be executable on-chain on Ethereum.💡 Gotcha: When designing programs intended to run on today’s on-chain Aqua instances, treat aquaInstructions as the authoritative list of runtime-available opcodes, and the rest of the instruction set as future / generic Swap VM capabilities.
Available instruction categories in the full Swap VM instruction set include:
STATIC_BALANCES_XD - Initialize static token balancesDYNAMIC_BALANCES_XD - Access and manipulate dynamic token balancesINVALIDATE_BIT_1D - Invalidate an order bit in the maker’s bitmapINVALIDATE_TOKEN_IN_1D - Invalidate orders by input tokenINVALIDATE_TOKEN_OUT_1D - Invalidate orders by output tokenJUMP - Unconditional jump to another instructionJUMP_IF_TOKEN_IN - Conditional jump based on taker input tokenJUMP_IF_TOKEN_OUT - Conditional jump based on taker output tokenDEADLINE - Guard: only execute before a given timestampONLY_TAKER_TOKEN_BALANCE_NON_ZERO - Guard: only execute if taker token balance is non-zeroONLY_TAKER_TOKEN_BALANCE_GTE - Guard: only execute if balance >= thresholdONLY_TAKER_TOKEN_SUPPLY_SHARE_GTE - Guard: only execute if supply share >= thresholdSALT - Add randomness to order hashXYC_SWAP_XD - XYC swap for multi-dimensional poolsCONCENTRATE_GROW_LIQUIDITY_XD - Concentrate liquidity in multi-dimensional poolsCONCENTRATE_GROW_LIQUIDITY_2D - Concentrate liquidity in 2D poolsDECAY_XD - Apply decay calculationLIMIT_SWAP_1D - Execute limit order swapLIMIT_SWAP_ONLY_FULL_1D - Execute limit order only if fully fillableREQUIRE_MIN_RATE_1D - Enforce minimum rate requirementADJUST_MIN_RATE_1D - Adjust minimum rate dynamicallyDUTCH_AUCTION_BALANCE_IN_1D - Dutch auction based on available input balanceDUTCH_AUCTION_BALANCE_OUT_1D - Dutch auction based on desired output balanceORACLE_PRICE_ADJUSTER_1D - Adjust prices based on oracle dataBASE_FEE_ADJUSTER_1D - Adjust for network base feesTWAP - Time-weighted average price swapEXTRUCTION - External contract instructionFLAT_FEE_AMOUNT_IN_XD - Flat fee based on input amountFLAT_FEE_AMOUNT_OUT_XD - Flat fee based on output amountPROGRESSIVE_FEE_IN_XD - Progressive fee applied on inputPROGRESSIVE_FEE_OUT_XD - Progressive fee applied on outputPROTOCOL_FEE_AMOUNT_OUT_XD - Protocol fee on outputAQUA_PROTOCOL_FEE_AMOUNT_OUT_XD - Aqua protocol fee on outputProgramBuilderAnyone can deploy a SwapVM-compatible contract with a custom instruction set (e.g. different opcode layout, subset, or extension of the core set) and still use this SDK to build programs for it.
The generic ProgramBuilder:
ixsSet: IOpcode[].SwapVM instruction set (_allInstructions)aquaInstructions)Take attention:
ProgramBuilder.add(ix) validates that the instruction’s opcode is present in the provided ixsSet.
ProgramBuilder.decode(program) uses the same ixsSet to map opcode indices back to instruction definitions, so your off-chain opcode table must match the on-chain contract layout.This makes it safe to:
SwapVM-style contract with a custom opcode mapping.ProgramBuilder with your custom ixsSet to construct and parse programs for that deployment, without changing the rest of the SDK.For strategies intended to run on today’s deployed AquaSwapVM contracts, it is recommended to use the specialized AquaProgramBuilder instead of the bare ProgramBuilder:
It is pre-wired with aquaInstructions, so you cannot accidentally use opcodes that are not supported by Aqua.
It exposes a rich set of high-level, typed methods for the Aqua instruction set đź’ˇ Practical guidance:
Use AquaProgramBuilder for real-world strategy building on current Aqua deployments – it gives you a safer, higher-level API over the Aqua opcode subset.
Use ProgramBuilder when:
SwapVM deployments (post-Fusaka on Ethereum), orA strategy is a reusable template that produces a SwapVmProgram – a sequence of instructions that defines how liquidity behaves and how swaps should be executed.
At a high level:
.build() method compiles these into a low-level SwapVmProgram using a program builder.Order and shipped.Strategies are thin wrappers around a program builder:
AquaProgramBuilder for current AquaSwapVM deployments (recommended).ProgramBuilder with a custom opcode set for non-Aqua/custom deployments..build() to get a SwapVmProgram.Because the strategy owns the builder, you can keep the strategy API stable even if the underlying instruction sequence evolves.
To define a custom strategy:
withX(...) methods to configure them..build():
ProgramBuilder.builder.build().This pattern keeps your business logic readable at the strategy layer while leveraging the full flexibility of the underlying Swap VM instruction set.
For example:
import type { SwapVmProgram } from '@1inch/swap-vm-sdk'
import { AquaProgramBuilder, instructions, Address, Order, MakerTraits } from '@1inch/swap-vm-sdk'
const { concentrate, fee } = instructions
/**
* Minimal strategy:
* - concentrates liquidity for a 2-token pool
* - optionally charges a taker fee on input
* - always finishes with a simple XYC swap
*/
export class SimpleAmmStrategy {
private liquidityA?: bigint
private liquidityB?: bigint
private feeBpsIn?: number
constructor(
public readonly tokenA: Address,
public readonly tokenB: Address,
) {}
/**
* Sets initial virtual liquidity for the pair.
*/
public withLiquidity(a: bigint, b: bigint): this {
this.liquidityA = a
this.liquidityB = b
return this
}
/**
* Sets taker fee (bps) applied to amountIn.
* If not called, no taker fee is applied.
*/
public withFeeTokenIn(bps: number): this {
this.feeBpsIn = bps
return this
}
/**
* Builds a SwapVmProgram for AquaSwapVM using a small, fixed instruction pipeline:
* [concentrate liquidity] -> [optional fee on input] -> [XYC swap]
*/
public build(): SwapVmProgram {
const builder = new AquaProgramBuilder()
if (this.liquidityA !== undefined && this.liquidityB !== undefined) {
const data = concentrate.ConcentrateGrowLiquidity2DArgs.fromTokenDeltas(
this.tokenA,
this.tokenB,
this.liquidityA,
this.liquidityB,
)
builder.add(concentrate.concentrateGrowLiquidity2D.createIx(data))
}
if (this.feeBpsIn !== undefined) {
const feeArgs = fee.FlatFeeArgs.fromBps(this.feeBpsIn)
builder.add(fee.flatFeeAmountInXD.createIx(feeArgs))
}
// Core swap step
builder.xycSwapXD()
return builder.build()
}
}
// Example usage:
const strategy = new SimpleAmmStrategy(USDC, WETH)
.withLiquidity(
10_000n * 10n ** 6n, // 10k USDC
5n * 10n ** 18n, // 5 WETH
)
.withFeeTokenIn(5) // 5 bps taker fee on input (optional)
const program = strategy.build()
const order = Order.new({
maker: new Address(maker),
program,
traits: MakerTraits.default(),
})
You can define your own high-level instructions as long as they:
Opcode definition wired into an instruction set.Here is an example of implementation flatFeeXD instruction. You can implement any custom instruction in the same way.
FlatFeeArgs)const FEE_100_PERCENT = 1e9 // 1e9 = 100%
/**
* Arguments for flat fee instruction
*/
export class FlatFeeArgs implements IArgsData {
public static readonly CODER = new FlatFeeArgsCoder()
constructor(public readonly fee: bigint) {
assert(fee >= 0n && fee <= UINT_32_MAX, `Invalid fee: ${fee}. Must be a valid uint32`)
assert(
fee <= BigInt(FEE_100_PERCENT),
`Fee out of range: ${fee}. Must be <= ${FEE_100_PERCENT}`,
)
}
/**
* Creates a FlatFeeArgs instance from basis points
* @param bps - Fee in basis points (10000 bps = 100%)
*/
public static fromBps(bps: number): FlatFeeArgs {
const fee = BigInt(bps * 100000)
return new FlatFeeArgs(fee)
}
}
FlatFeeArgsCoder)Coders:
IArgsCoder<T>.decode(encode(args)) === args.export class FlatFeeArgsCoder implements IArgsCoder<FlatFeeArgs> {
encode(args: FlatFeeArgs): HexString {
const builder = new BytesBuilder()
builder.addUint32(args.fee)
return new HexString(add0x(builder.asHex()))
}
decode(data: HexString): FlatFeeArgs {
const iter = BytesIter.BigInt(data.toString())
const fee = iter.nextUint32()
return new FlatFeeArgs(fee)
}
}
flatFeeXD)An Opcode ties together:
Symbol) for this instruction./**
* Applies flat fee to computed swap amount (same rate for exactIn and exactOut)
*/
export const flatFeeXD = new Opcode(Symbol('Fee.flatFeeXD'), FlatFeeArgs.CODER)
Once you have an Opcode:
flatFeeXD.createIx(args) produces a typed instruction.ProgramBuilder can add it to a program:
builder.add(flatFeeXD.createIx(FlatFeeArgs.fromBps(5))).To make your instruction usable at runtime, you must place it at the correct index in an instruction set that matches your on-chain VM:
export const myInstructionSet: Opcode<IArgsData>[] = [
/* ... previous opcodes ... */
fee.flatFeeXD,
/* ... */
]
⚠️ The array index in the instruction set (ixsSet[index]) must match the opcode index used by your on-chain contract. A mismatch will not fail at encoding time but will execute the wrong instruction at runtime.
The SDK includes pre-configured contract addresses of AquaSwapVMRouter for the following networks:
| Network | Chain ID | Address |
|---|---|---|
| Ethereum | 1 | 0x8fdd04dbf6111437b44bbca99c28882434e0958f |
| BNB Chain | 56 | 0x8fdd04dbf6111437b44bbca99c28882434e0958f |
| Polygon | 137 | 0x8fdd04dbf6111437b44bbca99c28882434e0958f |
| Arbitrum | 42161 | 0x8fdd04dbf6111437b44bbca99c28882434e0958f |
| Avalanche | 43114 | 0x8fdd04dbf6111437b44bbca99c28882434e0958f |
| Gnosis | 100 | 0x8fdd04dbf6111437b44bbca99c28882434e0958f |
| Coinbase Base | 8453 | 0x8fdd04dbf6111437b44bbca99c28882434e0958f |
| Optimism | 10 | 0x8fdd04dbf6111437b44bbca99c28882434e0958f |
| zkSync Era | 324 | 0x8fdd04dbf6111437b44bbca99c28882434e0958f |
| Linea | 59144 | 0x8fdd04dbf6111437b44bbca99c28882434e0958f |
| Unichain | 1301 | 0x8fdd04dbf6111437b44bbca99c28882434e0958f |
| Sonic | 146 | 0x8fdd04dbf6111437b44bbca99c28882434e0958f |
Access addresses using:
import { AQUA_SWAP_VM_CONTRACT_ADDRESSES, NetworkEnum } from '@1inch/swap-vm-sdk'
const ethereumAddress = AQUA_SWAP_VM_CONTRACT_ADDRESSES[NetworkEnum.ETHEREUM]
const arbitrumAddress = AQUA_SWAP_VM_CONTRACT_ADDRESSES[NetworkEnum.ARBITRUM]
The SDK exports:
SwapVMContract - Main contract class for encoding, decoding, and building transactionsAQUA_SWAP_VM_CONTRACT_ADDRESSES - Pre-configured contract addresses by networkSwappedEvent - Event class for parsing swapped eventsOrder - Order data structureMakerTraits - Maker-side configuration and flagsTakerTraits - Taker-side configuration and flagsABI - Contract ABI exportscontrols - Flow control instructionsbalances - Balance manipulation instructionsinvalidators - Invalidation instructionsxycSwap - XYC swap instructionsconcentrate - Liquidity concentration instructionsdecay - Decay calculation instructionslimitSwap - Limit order instructionsminRate - Minimum rate guard instructionsdutchAuction - Dutch auction instructionsoraclePriceAdjuster - Oracle-based price adjustmentbaseFeeAdjuster - Base fee adjustmenttwapSwap - Time-weighted average price instructionsextruction - External instruction callfee - Fee calculation instructionsThis SDK is provided under the terms described in LICENSE and THIRD_PARTY_NOTICES.
For any licensing questions or requests, contact:
FAQs
1inch Swap VM SDK
We found that @1inch/swap-vm-sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 6 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.

Security News
ENISA has become a CVE Program Root, giving the EU a central authority for coordinating vulnerability reporting, disclosure, and cross-border response.

Product
Socket now scans OpenVSX extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.