Documentation Index
Fetch the complete documentation index at: https://mintlify.com/1inch/cross-chain-sdk/llms.txt
Use this file to discover all available pages before exploring further.
The SDK provides utilities to decode events emitted by escrow contracts, allowing you to track cross-chain swap progress on-chain.
Overview
Escrow contracts emit events at key stages of the swap lifecycle:
- SrcEscrowCreated: When source chain escrow is deployed
- DstEscrowCreated: When destination chain escrow is deployed
- EscrowWithdrawal: When funds are withdrawn with secret
- EscrowCancelled: When an order is cancelled
- FundsRescued: When funds are rescued after timelock expiry
Event Classes
SrcEscrowCreated
Emitted when a source chain escrow contract is created.
Event Topic:
SrcEscrowCreatedEvent.TOPIC
// '0x1140dcf80f027f65ebd1c2e98c33e3ebf7ef025d944a079256037cd55271bf98'
Decoding:
import { SrcEscrowCreatedEvent } from '@1inch/cross-chain-sdk'
// From Web3/Ethers log
const log = await provider.getLogs({
topics: [SrcEscrowCreatedEvent.TOPIC],
fromBlock: 'latest'
})
// Decode the event
const event = SrcEscrowCreatedEvent.fromData(log[0].data)
console.log('Source Immutables:', {
orderHash: event.srcImmutables.orderHash,
maker: event.srcImmutables.maker.toString(),
taker: event.srcImmutables.taker.toString(),
token: event.srcImmutables.token.toString(),
amount: event.srcImmutables.amount.toString(),
safetyDeposit: event.srcImmutables.safetyDeposit.toString(),
hashlock: event.srcImmutables.hashLock.toString()
})
console.log('Destination Complement:', {
maker: event.dstImmutablesComplement.maker.toString(),
token: event.dstImmutablesComplement.token.toString(),
amount: event.dstImmutablesComplement.amount.toString(),
chainId: event.dstImmutablesComplement.chainId
})
Event Structure:
class SrcEscrowCreatedEvent {
srcImmutables: Immutables<EvmAddress>
dstImmutablesComplement: DstImmutablesComplement<AddressLike>
}
DstEscrowCreated
Emitted when a destination chain escrow contract is created.
Event Topic:
DstEscrowCreatedEvent.TOPIC
// '0xc30e111dcc74fddc2c3a4d98ffb97adec4485c0a687946bf5b22c2a99c7ff96d'
Decoding:
import { DstEscrowCreatedEvent } from '@1inch/cross-chain-sdk'
const log = await provider.getLogs({
topics: [DstEscrowCreatedEvent.TOPIC],
fromBlock: 'latest'
})
const event = DstEscrowCreatedEvent.fromData(log[0].data)
console.log('Destination Escrow Created:', {
escrow: event.escrow.toString(),
hashlock: event.hashlock,
taker: event.taker.toString()
})
Event Structure:
class DstEscrowCreatedEvent {
escrow: EvmAddress
hashlock: string
taker: EvmAddress
}
EscrowWithdrawal
Emitted when funds are withdrawn from an escrow (reveals the secret).
Event Topic:
EscrowWithdrawalEvent.TOPIC
// '0xe346f5c97a360db5188bfa5d3ec5f0583abde420c6ba4d08b6cfe61addc17105'
Decoding:
import { EscrowWithdrawalEvent } from '@1inch/cross-chain-sdk'
const log = await provider.getLogs({
topics: [EscrowWithdrawalEvent.TOPIC],
fromBlock: 'latest'
})
const event = EscrowWithdrawalEvent.fromData(log[0].data)
console.log('Secret revealed:', event.secret)
Event Structure:
class EscrowWithdrawalEvent {
secret: string
}
EscrowCancelled
Emitted when an escrow is cancelled.
Event Topic:
EscrowCancelledEvent.TOPIC
// '0x6e3be9294e58d10b9c8053cfd5e09871b67e442fe394d6b0870d336b9df984a9'
Event Structure:
class EscrowCancelledEvent {
escrowAddress: EvmAddress
}
FundsRescued
Emitted when funds are rescued after timelock expiry.
Event Topic:
FundsRescuedEvent.TOPIC
// '0xc4474c2790e13695f6d2b6f1d8e164290b55370f87a542fd7711abe0a1bf40ac'
Immutables Structure
The Immutables class contains all escrow parameters:
class Immutables<A extends AddressLike = AddressLike> {
orderHash: Buffer
hashLock: HashLock
maker: A
taker: A
token: A
amount: bigint
safetyDeposit: bigint
timeLocks: TimeLocks
fees?: ImmutableFees // v2.0+ only
}
Accessing Immutables Data
const event = SrcEscrowCreatedEvent.fromData(log.data)
const immutables = event.srcImmutables
// Get order hash
const orderHash = immutables.orderHash.toString('hex')
// Get addresses
const makerAddress = immutables.maker.toString()
const tokenAddress = immutables.token.toString()
// Get amounts
const amount = immutables.amount // bigint
const safetyDeposit = immutables.safetyDeposit // bigint
// Get hash lock
const hashlock = immutables.hashLock.toString()
// Get time locks
const timelocks = immutables.timeLocks.build() // bigint
// Get fees (v2.0+)
if (immutables.fees) {
const resolverFee = immutables.fees.resolverFeeAmount
const integratorFee = immutables.fees.integratorFeeAmount
}
Computing Immutables Hash
const hash = immutables.hash()
// Returns keccak256 hash matching contract's ImmutablesLib.hash()
JSON Serialization
const json = immutables.toJSON()
console.log(json)
// {
// orderHash: '0x...',
// hashlock: '0x...',
// maker: '0x...',
// taker: '0x...',
// token: '0x...',
// amount: '1000000000000000000',
// safetyDeposit: '100000000000000000',
// timelocks: '...',
// parameters: '0x...' // Encoded fees
// }
Fee Parameters (v2.0+)
Starting from v2.0, the Immutables structure includes fee parameters.
ImmutableFees Structure
class ImmutableFees {
resolverFeeAmount: bigint
integratorFeeAmount: bigint
resolverFeeRecipient: EvmAddress
integratorFeeRecipient: EvmAddress
}
Decoding Fee Parameters
import { ImmutableFees } from '@1inch/cross-chain-sdk'
// From event
const event = SrcEscrowCreatedEvent.fromData(log.data)
const fees = event.dstImmutablesComplement.fees
if (fees) {
console.log('Fee Parameters:', {
resolverFeeAmount: fees.resolverFeeAmount.toString(),
integratorFeeAmount: fees.integratorFeeAmount.toString(),
resolverFeeRecipient: fees.resolverFeeRecipient.toString(),
integratorFeeRecipient: fees.integratorFeeRecipient.toString()
})
}
// From encoded bytes
const feeBytes = '0x...' // From Immutables.parameters field
const decodedFees = ImmutableFees.decode(feeBytes)
console.log('Decoded fees:', decodedFees)
Fee Encoding
const fees = new ImmutableFees(
5556n, // resolverFeeAmount
231n, // integratorFeeAmount
EvmAddress.fromString('0x5375ea61702dc3f421dd3c0c63c6b32101102e22'),
EvmAddress.fromString('0x834704408a83c220ac4a85bf5c7c42307c4be4a5')
)
const encoded = fees.encode()
// Returns 128 bytes (256 hex chars + 0x prefix)
Zero Fees
const zeroFees = ImmutableFees.ZERO
// Check if fees are zero
if (fees.isZero()) {
console.log('No fees configured')
}
Practical Examples
Tracking Order Progress
import {
SrcEscrowCreatedEvent,
DstEscrowCreatedEvent,
EscrowWithdrawalEvent
} from '@1inch/cross-chain-sdk'
import { ethers } from 'ethers'
const provider = new ethers.JsonRpcProvider('https://rpc.example.com')
// Track source escrow creation
const srcLogs = await provider.getLogs({
address: escrowFactoryAddress,
topics: [SrcEscrowCreatedEvent.TOPIC],
fromBlock: startBlock,
toBlock: 'latest'
})
for (const log of srcLogs) {
const event = SrcEscrowCreatedEvent.fromData(log.data)
console.log(`Source escrow created for order ${event.srcImmutables.orderHash.toString('hex')}`)
}
// Track destination escrow creation
const dstLogs = await provider.getLogs({
address: escrowFactoryAddress,
topics: [DstEscrowCreatedEvent.TOPIC],
fromBlock: startBlock,
toBlock: 'latest'
})
for (const log of dstLogs) {
const event = DstEscrowCreatedEvent.fromData(log.data)
console.log(`Destination escrow created: ${event.escrow.toString()}`)
}
// Track withdrawals (secret reveals)
const withdrawalLogs = await provider.getLogs({
topics: [EscrowWithdrawalEvent.TOPIC],
fromBlock: startBlock,
toBlock: 'latest'
})
for (const log of withdrawalLogs) {
const event = EscrowWithdrawalEvent.fromData(log.data)
console.log(`Secret revealed: ${event.secret}`)
}
Computing Escrow Address
import { create2Address } from '@1inch/cross-chain-sdk'
const event = SrcEscrowCreatedEvent.fromData(log.data)
const immutables = event.srcImmutables
// Compute CREATE2 address
const escrowAddress = create2Address(
escrowFactoryAddress,
immutables.hash(),
implementationCodeHash
)
console.log('Predicted escrow address:', escrowAddress)
Monitoring Fee Distribution
const event = SrcEscrowCreatedEvent.fromData(log.data)
const fees = event.dstImmutablesComplement.fees
if (fees && !fees.isZero()) {
const totalFees = fees.resolverFeeAmount + fees.integratorFeeAmount
const dstAmount = event.dstImmutablesComplement.amount
console.log('Fee Distribution:', {
totalOutput: dstAmount.toString(),
resolverFee: fees.resolverFeeAmount.toString(),
integratorFee: fees.integratorFeeAmount.toString(),
totalFees: totalFees.toString(),
netAmount: (dstAmount - totalFees).toString(),
feePercentage: ((totalFees * 10000n) / dstAmount).toString() + ' bps'
})
}
Filtering by Order Hash
const targetOrderHash = '0x1234...'
const logs = await provider.getLogs({
address: escrowFactoryAddress,
topics: [SrcEscrowCreatedEvent.TOPIC],
fromBlock: startBlock,
toBlock: 'latest'
})
for (const log of logs) {
const event = SrcEscrowCreatedEvent.fromData(log.data)
const orderHash = event.srcImmutables.orderHash.toString('hex')
if (orderHash === targetOrderHash.slice(2)) {
console.log('Found escrow for order:', orderHash)
console.log('Source chain amount:', event.srcImmutables.amount.toString())
console.log('Destination chain amount:', event.dstImmutablesComplement.amount.toString())
break
}
}
Version Compatibility
v1.1 vs v2.0 Events
The SrcEscrowCreated event topic changed in v2.0:
| Version | Topic Hash |
|---|
| v1.1 | 0x0e534c62f0afd2fa0f0fa71198e8aa2d549f24daf2bb47de0d5486c7ce9288ca |
| v2.0 | 0x1140dcf80f027f65ebd1c2e98c33e3ebf7ef025d944a079256037cd55271bf98 |
Listening to both versions:
const V1_TOPIC = '0x0e534c62f0afd2fa0f0fa71198e8aa2d549f24daf2bb47de0d5486c7ce9288ca'
const V2_TOPIC = '0x1140dcf80f027f65ebd1c2e98c33e3ebf7ef025d944a079256037cd55271bf98'
const logs = await provider.getLogs({
address: escrowFactoryAddress,
topics: [[V1_TOPIC, V2_TOPIC]], // Listen for both
fromBlock: startBlock,
toBlock: 'latest'
})
for (const log of logs) {
if (log.topics[0] === V2_TOPIC) {
const event = SrcEscrowCreatedEvent.fromData(log.data)
console.log('v2.0 event with fees:', event.dstImmutablesComplement.fees)
} else {
// Handle v1.1 event (no fees)
console.log('v1.1 event without fees')
}
}
Parameters Field
The Immutables.parameters field was added in v2.0:
v1.1: No parameters field
v2.0: Contains encoded ImmutableFees (128 bytes when present, 0x when empty)
Error Handling
try {
const event = SrcEscrowCreatedEvent.fromData(log.data)
console.log('Event decoded successfully')
} catch (error) {
console.error('Failed to decode event:', error.message)
// Handle malformed log data
}
Best Practices
Use Block Ranges
Avoid querying too many blocks at once:
const BLOCK_RANGE = 1000
for (let block = startBlock; block <= endBlock; block += BLOCK_RANGE) {
const logs = await provider.getLogs({
topics: [SrcEscrowCreatedEvent.TOPIC],
fromBlock: block,
toBlock: Math.min(block + BLOCK_RANGE - 1, endBlock)
})
// Process logs
}
Cache Decoded Events
Avoid re-decoding the same events:
const eventCache = new Map<string, SrcEscrowCreatedEvent>()
function getOrDecodeEvent(log: Log): SrcEscrowCreatedEvent {
const key = `${log.blockHash}-${log.logIndex}`
if (!eventCache.has(key)) {
eventCache.set(key, SrcEscrowCreatedEvent.fromData(log.data))
}
return eventCache.get(key)!
}
Handle Chain Reorganizations
Monitor for block reorgs and reprocess affected events:
provider.on('block', async (blockNumber) => {
// Check if recent blocks were reorganized
// Re-fetch and re-process affected events
})