npm install '@1inch/limit-order-sdk'import {LimitOrder, MakerTraits, Address, Sdk, randBigInt, FetchProviderConnector} from "@1inch/limit-order-sdk"
import {UINT_40_MAX} from "@1inch/byte-utils"
import {Wallet} from 'ethers'
// it is a well-known test private key, do not use it in production
const privKey =
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
const authKey = '...'
const maker = new Wallet(privKey)
const expiresIn = 120n // 2m
const expiration = BigInt(Math.floor(Date.now() / 1000)) + expiresIn
// see MakerTraits.ts
const makerTraits = MakerTraits.default()
.withExpiration(expiration)
.withNonce(randBigInt(UINT_40_MAX))
const sdk = new Sdk({ authKey, networkId: 1, httpConnector: new FetchProviderConnector() })
const order = await sdk.createOrder({
makerAsset: new Address('0xdac17f958d2ee523a2206206994597c13d831ec7'),
takerAsset: new Address('0x111111111117dc0aa78b770fa6a738034120c302'),
makingAmount: 100_000000n, // 100 USDT
takingAmount: 10_00000000000000000n, // 10 1INCH
maker: new Address(maker.address),
// salt? : bigint
// receiver? : Address
}, makerTraits)
const typedData = order.getTypedData()
const signature = await maker.signTypedData(
typedData.domain,
{Order: typedData.types.Order},
typedData.message
)
await sdk.submitOrder(order, signature)When the limit-orders API returns integrator fee fields from /fee-info, Sdk.createOrder automatically:
- embeds
IntegratorFeefromintegratorFeeBps,integratorFeeReceiver, andintegratorFeeSharePercent - sets the salt track code from
source(only whenorderInfo.saltis omitted)
integratorFeeSharePercent is a whole-number percent (the API rejects fractional rev-share). If fee bps is set but share is missing, the SDK treats the response as malformed and uses a zero integrator fee. Pass extra.integratorFee to override. Integrators without fee config are unaffected — orders keep a zero integrator fee as before.
Source / track code: the API returns bare hex (e.g. aba10994), not 0x-prefixed. setSource keccak-hashes non-0x values into the salt track bits — do not “fix” the API value by adding 0x, or attribution will break. If you pass an explicit orderInfo.salt, the API source is not applied; your salt’s track bits win.
Bps.fromPercent / fromSharePercent: values with more than 2 decimal places are truncated to 1 bps precision (e.g. 0.125 → 12 bps) instead of throwing. Negative values are rejected.
By default a limit order can be filled in several parts. To create an order that must be filled entirely in a single transaction - or not at all - disable partial fills:
import {MakerTraits, randBigInt} from "@1inch/limit-order-sdk"
import {UINT_40_MAX} from "@1inch/byte-utils"
const expiration = BigInt(Math.floor(Date.now() / 1000)) + 3600n // 1h
const makerTraits = MakerTraits.default()
.withExpiration(expiration)
.withNonce(randBigInt(UINT_40_MAX)) // required: unique nonce per order
.disablePartialFills()
.disableMultipleFills()
// then create, sign and submit the order as usual - see "Order creation" aboveRules:
- Give every such order its own random nonce via
withNonce- never reuse a nonce across active orders. - Do not call
withEpochon these orders - submit rejects fill-or-kill orders that use epoch. - If the order cannot be filled in full right away, it stays open until it fills, expires or is cancelled. It will never be filled partially.
The orderbook API returns partialFillsAllowed: false for these orders.
Cancellation is on-chain, using the maker traits and the hash of the order (keep both after submitting):
import {getLimitOrderContract} from "@1inch/limit-order-sdk"
import {Contract, JsonRpcProvider, Wallet} from "ethers"
const chainId = 1 // same chainId as create/submit
const abi = [
'function cancelOrder(uint256 makerTraits, bytes32 orderHash)',
'function cancelOrders(uint256[] makerTraits, bytes32[] orderHashes)'
]
const signer = new Wallet(privKey, new JsonRpcProvider(rpcUrl))
const lop = new Contract(getLimitOrderContract(chainId), abi, signer)
// keep after submit
const traits = order.build().makerTraits // string
const orderHash = order.getOrderHash(chainId)
// single order
await (await lop.cancelOrder(BigInt(traits), orderHash)).wait()
// several orders in one transaction (traits[i] must belong to hashes[i])
await (await lop.cancelOrders(
openOrders.map((o) => BigInt(o.build().makerTraits)),
openOrders.map((o) => o.getOrderHash(chainId))
)).wait()Note: cancelling all orders by epoch (increaseEpoch) does not affect orders with partial fills disabled - cancel them by hash as shown above.
RfqOrder is a light, gas efficient version of LimitOrder, but it does not support multiple fills and extension
Mainly used by market makers
import {RfqOrder, Address, randBigInt} from "@1inch/limit-order-sdk"
import {UINT_40_MAX} from "@1inch/byte-utils"
import {Wallet} from 'ethers'
// it is a well-known test private key, do not use it in production
const privKey =
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
const maker = new Wallet(privKey)
const expiresIn = 120n // 2m
const expiration = BigInt(Math.floor(Date.now() / 1000)) + expiresIn
const order = new RfqOrder({
makerAsset: new Address('0xdac17f958d2ee523a2206206994597c13d831ec7'),
takerAsset: new Address('0x111111111117dc0aa78b770fa6a738034120c302'),
makingAmount: 100_000000n, // 100 USDT
takingAmount: 10_00000000000000000n, // 10 1INCH
maker: new Address(maker.address)
}, {
allowedSender: new Address('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'),
expiration,
nonce: randBigInt(UINT_40_MAX),
})
const typedData = order.getTypedData()
const signature = await maker.signTypedData(
typedData.domain,
{Order: typedData.types.Order},
typedData.message
)To execute a limit order, you need to build the appropriate calldata using the LimitOrderContract class. There are different methods depending on whether the order has extensions/interactions and whether the maker is an EOA or smart contract.
import {LimitOrderContract, TakerTraits, LimitOrder} from '@1inch/limit-order-sdk'
// Assume you already have a FusionOrder in `order` variable
const order = ... // your LimitOrder instance
const signature = '0x...' // order signature
const amount = 100_000000n // amount to fill (in taker or maker asset units, based on set `AmountMode`)
// Create taker traits
const takerTraits = TakerTraits.default()
// Optional: Configure taker preferences
// .setAmountMode(AmountMode.TakerAmount) // or MakerAmount
// .enableNativeUnwrap() // for WETH -> ETH conversion
// .setAmountThreshold(minAmount) // minimum/maximum acceptable amount (based on set `AmountMode`)
// Build calldata for different scenarios:
// 1. Simple order fill (no extensions, no interactions)
const simpleCalldata = LimitOrderContract.getFillOrderCalldata(
order.build(), // converts to LimitOrderV4Struct
signature,
takerTraits,
amount
)
// 2. Fill contract order (when maker is a smart contract)
const contractCalldata = LimitOrderContract.getFillContractOrderCalldata(
order.build(),
signature,
takerTraits,
amount
)
// 3. Order with extensions or taker interactions
const extension = '0x...' // extension calldata
const interaction = '0x...' // taker interaction calldata
const takerTraitsWithArgs = TakerTraits.default()
.setExtension(extension)
.setInteraction(interaction)
// .setReceiver(receiverAddress) // optional: custom receiver
const argsCalldata = LimitOrderContract.getFillOrderArgsCalldata(
order.build(),
signature,
takerTraitsWithArgs,
amount
)
// 4. Contract order with extensions/interactions
const contractArgsCalldata = LimitOrderContract.getFillContractOrderArgsCalldata(
order.build(),
signature,
takerTraitsWithArgs,
amount
)The calldata should be sent to the 1inch Limit Order Protocol contract addresses can be found at docs
TakerTraits allows you to configure various execution parameters:
import {TakerTraits, AmountMode, Address} from '@1inch/limit-order-sdk'
const takerTraits = TakerTraits.default()
// Set amount calculation mode
.setAmountMode(AmountMode.MakerAmount) // fill by maker amount
// or
// .setAmountMode(AmountMode.TakerAmount) // fill by taker amount (default)
// Enable WETH unwrapping to ETH
.enableNativeUnwrap()
// Skip order permit (if not needed)
.skipOrderPermit()
// Enable Permit2
.enablePermit2()
// Set amount threshold
.setAmountThreshold(1000000n)
// Set custom receiver for maker assets
.setReceiver(new Address('0x...'))
// Add extension calldata (for order extensions)
.setExtension('0x...')
// Add taker interaction calldata
.setInteraction('0x...')| Method | Use When |
|---|---|
getFillOrderCalldata |
EOA maker, no extensions/interactions |
getFillContractOrderCalldata |
Smart contract maker, no extensions/interactions |
getFillOrderArgsCalldata |
EOA maker, with extensions/interactions |
getFillContractOrderArgsCalldata |
Smart contract maker, with extensions/interactions |
import {Api, FetchProviderConnector, LimitOrder, HttpProviderConnector} from '@1inch/limit-order-sdk'
const networkId = 1 // ethereum
const api = new Api({
networkId,
authKey: 'key', // get it at https://portal.1inch.dev/
httpConnector: new FetchProviderConnector() // or use any connector which implements `HttpProviderConnector`
})
// submit order
const order = ... /// see `Order creation` section
const signature = '0x'
await api.submitOrder(order, signature)
// get order by hash
const orderHash = order.getOrderHash(networkId)
const orderInfo = await api.getOrderByHash(orderHash)
// get orders by maker with cursor pagination
import { CursorPager } from '@1inch/limit-order-sdk'
// First page - no cursor needed
const firstPager = new CursorPager({ limit: 10 })
const response = await api.getOrdersByMaker(order.maker, {
pager: firstPager,
statuses: [1] // only valid orders
})
const orders = response.items
const { hasMore, nextCursor, count } = response.meta
// Get next page if available
if (hasMore && nextCursor) {
const nextPager = new CursorPager({ limit: 10, cursor: nextCursor })
const nextPage = await api.getOrdersByMaker(order.maker, {
pager: nextPager,
statuses: [1]
})
}
// Or use without explicit pager (defaults to limit: 100, no cursor)
const makerOrders = await api.getOrdersByMaker(order.maker, {
statuses: [1]
})
// get all orders from orderbook with pagination
const allOrdersPager = new CursorPager({ limit: 20 })
const allOrdersResponse = await api.getAllOrders({
pager: allOrdersPager,
statuses: [1, 2] // valid and temporarily invalid orders
})
// pagination works the same way
if (allOrdersResponse.meta.hasMore && allOrdersResponse.meta.nextCursor) {
const nextAllOrders = await api.getAllOrders({
pager: new CursorPager({
limit: 20,
cursor: allOrdersResponse.meta.nextCursor
})
})
}axios package should be installed
import {Api, LimitOrder} from "@1inch/limit-order-sdk"
import {AxiosProviderConnector} from '@1inch/limit-order-sdk/axios'
const api = new Api({
networkId: 1, // ethereum
authKey: 'key', // get it at https://portal.1inch.dev/
httpConnector: new AxiosProviderConnector()
})Install dependencies
pnpm installRun tests
pnpm testIntegration tests are inside tests folder. They use foundry fork node and execute transaction on it.
Install dependencies
pnpm install && forge installRun tests
pnpm test:integration