Untuk resolver

Mengisi swap terhadap likuiditas Aqua: apa yang dibutuhkan peran resolver, bagaimana sebuah fill berjalan on-chain, dan cara mengutip lalu mengeksekusinya dengan SwapVM SDK.

10 menit bacaDiperbarui Juli 2026

Apa yang dilakukan resolver di Aqua

Di seluruh 1inch Network, swap yang mengisi likuiditas Aqua dirutekan oleh 1inch Resolver: pembuat pasar dan trader arbitrase yang menyelesaikan proses verifikasi 1inch.

Aqua sendiri tidak melakukan discovery maupun matching. Ia menetapkan harga dan mengeksekusi satu posisi terhadap satu pihak lawan per panggilan swap. Menemukan posisi mana yang diisi, dan seberapa besar, adalah tugas resolver: routing 1inch menyerahkan swap ke jaringan, dan sistem Anda sendiri dapat memanggil kontrak secara langsung.

Baru dengan mekanisme dasarnya? Mulai dari cara kerja Aqua.

Sebelum mulai

  • Verifikasi resolver melalui portal 1inch Business, yang memberikan token akses per chain
  • Token akses pada EOA operator yang mengirim transaksi swap
  • Akses node di chain target, plus token input dan gas untuk fill
  • Alamat kontrak kanonik, identik di setiap chain yang didukung dan tercantum di bawah
  • Kunci API dari Business portal untuk jalur penemuan Aqua API

Alamat kontrak

Aqua dan router SwapVM adalah deployment deterministik dengan alamat yang sama di setiap chain yang didukung. Berinteraksilah hanya dengan dua kontrak ini. Selain itu bukan Aqua.

Aqua (registri)
0x1111113ccf1426a8e30e2bff5e005d929bf6a90a
Router SwapVM
0x111111338c5091e8440b67b168bae16a668ac0de

Cara kerja sebuah fill

  1. 1

    Lakukan verifikasi

    Selesaikan onboarding resolver melalui portal Business dan terima token akses untuk setiap chain tempat Anda mengisi.

  2. 2

    Temukan posisi

    Ambil posisi terbuka dari Aqua API, bangun ulang set aktif dari event Shipped dan Docked, atau terima swap dari routing 1inch sebagai resolver jaringan.

  3. 3

    Kutip tepat sebelum mengirim

    Panggil fungsi quote router lewat static call dengan order yang sudah didekode. Kutipan membaca dukungan dompet live, jadi ikut bergeser saat fill lain masuk.

  4. 4

    Tetapkan batas Anda

    Turunkan output minimum dari kutipan terbaru dan pasang deadline pendek. Kurva yang bergeser lalu revert alih-alih terisi di kurs yang lebih buruk.

  5. 5

    Swap dan verifikasi

    Kirim swap dari EOA pemegang token akses, wajibkan resi sukses, dan baca jumlah yang tereksekusi dari event Swapped.

Quickstart: kutip dan isi satu posisi

Contoh di bawah menemukan posisi terbuka lewat Aqua API, mengambil quote, lalu mengirim pengisian terlindungi. Berjalan di Node 22 dengan SDK TypeScript. Kontrak, event, SDK, dan API menyebut posisi sebagai strategy, jadi kodenya juga.

Instal SDKbash
pnpm add @1inch/aqua-sdk @1inch/swap-vm-sdk viem
Temukan posisi terbuka lewat Aqua APItypescript
import assert from 'node:assert'
import { HexString, Order } from '@1inch/swap-vm-sdk'

// Every currently open position from every LP, newest first. Auth is the
// same API key the other 1inch APIs use - issued in the Business portal.
const response = await fetch('https://api.1inch.com/aqua/v1.0/strategies/opened?chainIds=1&limit=50', {
  headers: { Authorization: `Bearer ${process.env.ONEINCH_API_KEY}` },
})
assert(response.ok, `Aqua API responded ${response.status}`)
const { items, nextCursor } = await response.json()

// Pick by your own criteria. Per-token balance and allowance in each item are
// useful pre-filters, but they are indexed with a delay - only a fresh
// on-chain quote() is authoritative.
const strategy = items[0]
const order = Order.decode(new HexString(strategy.strategyBytes))
console.log('candidate:', strategy.strategyHash, 'tokens:', strategy.tokens.length, 'more:', nextCursor !== null)
Kutip, isi, dan verifikasitypescript
import assert from 'node:assert'
import { ABI, Address, HexString, Order, SwappedEvent, SwapVMContract, TakerTraits } from '@1inch/swap-vm-sdk'
import { createPublicClient, createWalletClient, decodeFunctionResult, erc20Abi, http, isHex } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'

// The SwapVM router is a deterministic deployment - the same address on every
// supported chain (see the contract addresses above). The strategy bytes come
// from the Aqua API or a Shipped event. The operator key belongs to the EOA
// holding the resolver credential - it must be the transaction origin.
const router = new Address('0x111111338c5091e8440b67b168bae16a668ac0de')
const strategyBytes = process.env.STRATEGY_BYTES
const operatorPrivateKey = process.env.OPERATOR_PRIVATE_KEY
assert(isHex(strategyBytes) && isHex(operatorPrivateKey))

const order = Order.decode(new HexString(strategyBytes))

const USDC = new Address('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48')
const WETH = new Address('0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2')
const amountIn = 3_000n * 10n ** 6n

const operator = privateKeyToAccount(operatorPrivateKey)
const publicClient = createPublicClient({ chain: mainnet, transport: http() })
const wallet = createWalletClient({ chain: mainnet, transport: http(), account: operator })

// 1. Preview the swap with a static quote() call, right before you submit.
const quoteTx = SwapVMContract.buildQuoteTx(router, {
  order,
  tokenIn: USDC,
  tokenOut: WETH,
  amount: amountIn,
  takerTraits: TakerTraits.new({ exactIn: true }),
})
const quoted = await publicClient.call({ to: quoteTx.to, data: quoteTx.data })
assert(quoted.data, 'quote call returned no data')
const [, quotedOut] = decodeFunctionResult({ abi: ABI.SWAP_VM_ABI, functionName: 'quote', data: quoted.data })
console.log('quoted output:', quotedOut)

// 2. Approve the router to move the input token (once per token and chain).
const approveHash = await wallet.writeContract({
  address: USDC.toString(),
  abi: erc20Abi,
  functionName: 'approve',
  args: [router.toString(), amountIn],
})
await publicClient.waitForTransactionReceipt({ hash: approveHash })

// 3. Swap with a minimum-output floor and a short deadline. Balances and
// curves move between quote and fill - never submit unprotected traits.
const swapTx = SwapVMContract.buildSwapTx(router, {
  order,
  tokenIn: USDC,
  tokenOut: WETH,
  amount: amountIn,
  takerTraits: TakerTraits.new({
    exactIn: true,
    threshold: (quotedOut * 995n) / 1_000n,
    deadline: BigInt(Math.floor(Date.now() / 1_000) + 60),
  }),
})
const fillHash = await wallet.sendTransaction(swapTx)
const receipt = await publicClient.waitForTransactionReceipt({ hash: fillHash })
assert(receipt.status === 'success', 'fill reverted')

// 4. Verify the executed amounts from the router's Swapped event.
const swappedLog = receipt.logs.find((log) => log.topics[0] === SwappedEvent.TOPIC.toString())
assert(swappedLog, 'no Swapped event in the receipt')
const swapped = SwappedEvent.fromLog(swappedLog)
console.log('filled:', swapped.amountIn, '->', swapped.amountOut)

Coba dulu seluruh alur di fork

Semua di atas bisa diuji dengan aman di fork lokal. Anvil dari Foundry mengkloning chain pada satu blok, jadi Anda mendapat kontrak asli dan posisi aktif asli tanpa taruhan apa pun. Dengan pengiriman tanpa kunci diaktifkan, Anda dapat bertindak sebagai EOA mana pun yang sudah memegang token akses dan menjalani seluruh alur, menemukan, mengutip, mengisi, memverifikasi, sebelum transaksi nyata pertama Anda.

Uji coba pada fork mainnetbash
# Real Aqua bytecode and live positions at the forked block, zero real spend
anvil --fork-url $YOUR_RPC_URL --auto-impersonate

# Point the quickstart at http://127.0.0.1:8545 and send from any EOA that
# already holds the per-chain access token - no key needed on a fork

Bagaimana pengisian dieksekusi on-chain

Pengisian adalah satu transaksi ke router SwapVM. Router menjalankan program instruksi posisi: pemeriksaan akses dulu, lalu kurva harga, lalu perpindahan token. Token masukan berpindah dari EOA Anda ke wallet LP dan token keluaran kembali kepada Anda dalam transaksi yang sama, sementara registri Aqua memperbarui saldo posisi dan memancarkan Pushed dan Pulled. Tidak ada yang berada di pool pada titik mana pun.

Semuanya serba penuh atau batal. Jika ada pemeriksaan yang gagal saat eksekusi, token akses hilang, threshold tidak terpenuhi, deadline lewat, atau dukungan wallet terlalu rendah, seluruh transaksi revert dan tidak ada token yang berpindah. Pengisian yang revert hanya memakan gas.

Router menyediakan quote dan swap, dan keduanya menjalankan jalur harga yang sama. Keduanya bukan fungsi view, jadi panggil quote lewat eth_call sebagai panggilan statis: ia membaca keadaan langsung, menghargai persis swap yang Anda berikan, dan tidak mengubah apa pun. Pratinjau itu bukan komitmen. Hanya traits yang Anda kirim bersama swap yang mengikat eksekusi.

TakerTraits membawa batas eksekusi Anda ke dalam transaksi. Chain yang menegakkannya, bukan SDK. Yang paling sering dipakai:

exactIn
Sisi mana yang tetap. Dengan masukan pasti Anda menetapkan jumlah yang dikirim dan membatasi yang diterima. Dengan keluaran pasti Anda menetapkan yang diterima dan membatasi yang dikirim.
threshold
Batasnya sendiri. Pada masukan pasti, keluaran minimum yang harus diberikan pengisian. Pada keluaran pasti, plafon yang Anda belanjakan. Threshold nol menonaktifkan pemeriksaan, jadi selalu turunkan dari quote yang baru.
deadline
Kedaluwarsa dalam detik unix. Transaksi yang ditambang setelahnya revert, sehingga pengisian yang tersangkut di mempool tidak bisa dieksekusi terhadap kurva usang.
customReceiver
Mengirim keluaran ke alamat selain EOA pengirim, misalnya alamat treasury. Pemeriksaan akses tetap berjalan terhadap asal transaksi.
shouldUnwrap
Terima token asli alih-alih bentuk terbungkus saat keluarannya token asli terbungkus.

Jangan percaya hitungan sendiri untuk hasilnya. Wajibkan resi sukses, lalu dekode event Swapped milik router: orderHash, maker, taker, tokenIn, tokenOut, amountIn, dan amountOut. Itulah jumlah yang dieksekusi, dan itulah yang harus dicatat pembukuan Anda.

Mode kegagalan yang perlu ditangani

Posisi ditutup
LP dapat menutup posisi kapan saja, dan pembacaan saldo revert begitu posisi hilang. Posisi yang tidak ada di daftar opened API berarti tertutup, tetapi di antara polling, revert on-chain tetap sumber kebenaran. Periksa ulang sebelum setiap pengisian.
Dukungan dompet rendah
Posisi memberi quote dari saldo wallet bersama. Pengisian pesaing bisa mengurasnya lebih dulu, sehingga transfer Anda revert meski quote tampak baik. Field balance dan allowance dari API membantu pra-filter, tetapi diindeks dengan jeda. Hanya quote on-chain yang baru yang otoritatif.
Harga bergeser
Kutipan menjadi basi saat fill masuk dan waktu berlalu. Batas output minimum dan deadline mengubah fill buruk menjadi revert yang bersih.
Token akses tidak ada
Tanpa kredensial pada asal transaksi, posisi buatan dApp me-revert swap sebelum logika harga berjalan.
Alamat non-kanonik
Hanya dua alamat kanonik di atas yang merupakan Aqua. Pengisian yang dikirim ke tempat lain tidak mencapai posisi aktif. Tidak ada yang perlu diverifikasi per chain, deployment identik di mana-mana.

Beroperasi di produksi

Perlakukan EOA operator sebagai kredensial, bukan sekadar wallet. Ia memegang token akses per chain, jadi isolasi kuncinya di penandatangan khusus, simpan hanya inventaris kerja dan gas di alamat itu, dan jangan pakai untuk hal lain.

Jadikan estimasi gas gerbang terakhir Anda. Pustaka wallet mengestimasi gas sebelum menyiarkan, dan estimasi yang gagal adalah revert yang muncul lebih awal, sebelum apa pun terkirim. Anggap itu pengisian yang dilewati dan lanjut ke kandidat berikutnya alih-alih mengulang membabi buta.

Pantau tiga sinyal. Tingkat revert Anda, yang naik saat data penemuan basi atau ukuran terlalu dekat ke dukungan. Umur quote di balik setiap pengisian, yang seharusnya tetap hitungan detik. Dan jumlah tereksekusi dari Swapped dibanding yang Anda kutip, yang menangkap penyimpangan sebelum merugikan.

Menemukan posisi di produksi

Dua jalur memberi Anda set aktif. Aqua API adalah cara tercepat untuk mulai. Membangun ulang dari event bersifat trustless dan tanpa dependensi eksternal. Keduanya masuk ke alur quote dan pengisian yang sama.

Aqua API mencantumkan semua posisi yang sedang terbuka dari setiap LP: GET /v1.0/strategies/opened di api.1inch.com/aqua, dengan paginasi kursor hingga 500 item per halaman serta filter chain dan app. Setiap item memuat strategyBytes yang Anda berikan ke Order.decode, plus balance dan allowance per token untuk pra-filter kandidat. Permintaan memerlukan kunci API yang sama dengan API 1inch lainnya, diterbitkan di Business portal. Indeks sedikit tertinggal dari chain, jadi selalu minta quote on-chain baru sebelum mengisi.

Registry Aqua, kontrak inti protokol, memancarkan Shipped saat posisi dibuka dan Docked saat ditutup. Set live adalah Shipped dikurangi Docked, dibangun ulang dari log mulai blok deployment tiap chain. Field event berada di data log, bukan di topics: filter berdasarkan alamat kontrak dan signature event, lalu dekode dan cocokkan di sisi klien.

Bentuk event-nya kecil. Shipped memuat maker, app, strategyHash, dan bytes strategi lengkap. Docked memuat maker, app, dan strategyHash. SDK menyertakan pembantu bertipe untuk keduanya, ShippedEvent dan DockedEvent, dengan dekoder fromLog dan konstanta TOPIC, jadi Anda tidak pernah menulis ABI secara manual.

Bangun ulang set aktif dari eventtypescript
import { DockedEvent, ShippedEvent } from '@1inch/aqua-sdk'
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'

const AQUA = '0x1111113ccf1426a8e30e2bff5e005d929bf6a90a'
const publicClient = createPublicClient({ chain: mainnet, transport: http() })

// Shipped and Docked carry every field in the log data, none in topics, so
// pull the registry's logs and match on the event signature client-side.
const logs = await publicClient.getLogs({
  address: AQUA,
  fromBlock: 23_000_000n, // the per-chain deployment block, or your last checkpoint
  toBlock: 'latest',
})

const live = new Map<string, ShippedEvent>()
for (const log of logs) {
  if (log.topics[0] === ShippedEvent.TOPIC.toString()) {
    const shipped = ShippedEvent.fromLog(log)
    live.set(shipped.strategyHash.toString(), shipped)
  } else if (log.topics[0] === DockedEvent.TOPIC.toString()) {
    live.delete(DockedEvent.fromLog(log).strategyHash.toString())
  }
}

// live now maps strategyHash -> Shipped payload: maker, app and the strategy
// bytes you decode with Order.decode before quoting.
console.log('open positions:', live.size)

Pembacaan on-chain memberi sisanya. View rawBalances dan safeBalances milik registri melaporkan dukungan wallet di balik posisi, dan event Swapped milik router memuat swap yang dieksekusi. Jaga quote tetap segar alih-alih menyimpannya.

Menentukan ukuran pengisian dimulai dari dukungan, bukan dari quote. Baca dukungan posisi lewat view registri, jaga ukuran Anda jauh di bawahnya, lalu ambil quote baru untuk ukuran persis itu tepat sebelum mengirim. Field balance dan allowance dari API adalah saringan awal yang murah untuk banyak kandidat, view dan quote adalah kebenaran untuk satu.

FAQ resolver

Tidak. Pemeriksaan akses mensyaratkan asal transaksi adalah EOA pemegang token akses, jadi wallet kontrak dan bundler tidak bisa melewatinya. Kirim pengisian dari EOA operator terverifikasi.

Tidak. Fungsi quote adalah pratinjau statis keadaan langsung dan tidak memindahkan apa pun. Hanya TakerTraits yang dikirim bersama swap yang mengikat eksekusi: threshold dan deadline ditegakkan on-chain.

Gas saja. Pemeriksaan yang gagal me-revert seluruh transaksi, jadi tidak ada token yang berpindah di kedua sisi.

Verifikasi lewat 1inch Business portal memberi token akses per chain. EOA operator memerlukan token itu di setiap chain tempat Anda mengisi.

Referensi Aqua API Endpoint, parameter, dan bentuk respons untuk penemuan posisi dan statistik, di Business portal. Aqua SDK & SwapVM SDK Builder bertipe, dekoder, dan parser event untuk alur fill, di repo 1inch/sdks. Onboarding resolver Langkah verifikasi dan dokumentasi resolver di portal 1inch Business. White paper Aqua Desain lengkap lapisan likuiditas bersama.

Siap mengisi likuiditas Aqua?

Mulai verifikasi dan hubungi tim melalui portal 1inch Business.

Buka portal Business