VifRouter
The VifRouter class is the main entry point for building and executing transactions with the Vif protocol.
Initialization
import { VifRouter } from 'vifdk'
const router = new VifRouter(
routerAddress, // VifRouter contract address
coreAddress, // Vif core contract address
chainId // Network chain ID
)Creating Actions
VifRouter provides two methods for creating action builders:
createTypedActions()
Use when actions are known in advance - provides better TypeScript support and autocomplete:
const actions = router.createTypedActions()
.orderSingle({ /* typed params */ })
.settleAll(/* typed token */)
.build()createActions()
Use when actions are unknown in advance - for dynamic flows (loops, conditionals, user-driven):
const actions = router.createActions()
// Build actions dynamically
.build()Building Transactions
Actions use a fluent builder pattern:
const actions = router
.createTypedActions()
.action1(params)
.action2(params)
.action3(params)
.build(options)Build Options
.build({
addRecommendedActions?: boolean // Auto-add settlements
receiver?: Address // Default receiver for takes
})addRecommendedActions: Automatically adds necessary settleAll and takeAll actions based on the operations performed.
const actions = router
.createTypedActions()
.orderSingle({
market: market.asks,
fillVolume: USDC.amount('1000')
})
.build({
addRecommendedActions: true,
receiver: walletAddress
})
// Automatically adds settleAll(USDC) and takeAll(WETH)Getting Transaction Data
txData()
Returns the encoded commands and arguments for the VifRouter contract:
const actions = router.createTypedActions()
.orderSingle({ /* ... */ })
.build()
const { commands, args } = actions.txData()Use with viem to execute the transaction:
import { execute } from 'vifdk'
const hash = await walletClient.writeContract({
address: routerAddress,
...execute(commands, args),
value: actions.expectedValue({ globalProvision })
})expectedValue()
Calculates the native token value needed for the transaction:
const value = actions.expectedValue({
globalProvision: Token.PROVISION_TOKEN.amount('0.001')
})This includes:
- Provisions for limit orders with expiry
- Native token wrapping amounts
- Any other native token settlements
expectedAllowances()
Returns required token approvals:
const approvals = actions.expectedAllowances()
for (const approval of approvals) {
console.log(`Approve ${approval.amountString} ${approval.token.symbol}`)
// Check and approve if needed
const currentAllowance = await client.readContract({
address: approval.token.address,
abi: erc20Abi,
functionName: 'allowance',
args: [walletAddress, coreAddress]
})
if (currentAllowance < approval.amount) {
await walletClient.writeContract({
address: approval.token.address,
abi: erc20Abi,
functionName: 'approve',
args: [coreAddress, approval.amount]
})
}
}Parsing Results
parseSimulationResult()
Parse the result from a simulation:
const { result } = await client.simulateContract({
address: routerAddress,
...execute(commands, args)
})
const parsed = actions.parseSimulationResult(result)
for (const actionResult of parsed) {
console.log(`Action: ${actionResult.type}`)
console.log(`Success: ${actionResult.success}`)
if (actionResult.data) {
// Data is typed based on action type
console.log('Data:', actionResult.data)
}
if (actionResult.error) {
console.log('Error:', actionResult.error)
}
}parseLogs()
Parse transaction receipt logs:
const receipt = await client.waitForTransactionReceipt({ hash })
const results = actions.parseLogs(receipt.logs)
// results[0] contains the first action's result
if (results[0].type === Action.ORDER_SINGLE && results[0].data) {
console.log('Gave:', results[0].data.gave.amountString)
console.log('Got:', results[0].data.got.amountString)
}Complete Example
import { VifRouter, Token, Market, Action } from 'vifdk'
import { createWalletClient } from 'viem'
// Initialize
const router = new VifRouter(routerAddress, coreAddress, 1)
const market = Market.from({
base: WETH,
quote: USDC,
tickSpacing: 1n
})
// Build actions
const actions = router
.createTypedActions()
.orderSingle({
market: market.asks,
fillVolume: USDC.amount('1000'),
maxTick: market.asks.price(4000)
})
.build({
addRecommendedActions: true,
receiver: walletAddress
})
// Check approvals
const approvals = actions.expectedAllowances()
for (const approval of approvals) {
// Approve tokens...
}
// Simulate
const { result, request } = await client.simulateContract({
address: routerAddress,
...execute(...actions.txData())
})
// Parse simulation
const simResult = actions.parseSimulationResult(result)
console.log('Expected output:', simResult[0].data.got.amountString)
// Execute
const hash = await walletClient.writeContract(request)
// Parse receipt
const receipt = await client.waitForTransactionReceipt({ hash })
const results = actions.parseLogs(receipt.logs)
console.log('Actual output:', results[0].data.got.amountString)Authorization
For signature-based authorization (EIP-712):
authorizationData()
Create authorization data for signing:
const auth = router.authorizationData(
userAddress,
nonce,
deadline
)singatureDataForAuthorization()
Get typed data for wallet signing:
const typedData = router.singatureDataForAuthorization(auth)
const signature = await walletClient.signTypedData(typedData)Then use the signature with the authorize action.
Error Handling
Actions can be marked as failable:
import { Action, toFailableAction } from 'vifdk'
const actions = router
.createActions()
.add(Action.ORDER_SINGLE, params) // Will revert if fails
.add(toFailableAction(Action.ORDER_SINGLE), params) // Won't revert
.build()Results indicate success/failure:
const results = actions.parseSimulationResult(result)
for (const res of results) {
if (!res.success) {
console.error(`Action ${res.type} failed:`, res.error)
}
}Best Practices
Always Simulate First
// ✓ Good: Simulate before executing
const { result, request } = await client.simulateContract({ /* ... */ })
const simResult = actions.parseSimulationResult(result)
// Check simResult
await walletClient.writeContract(request)
// ✗ Bad: Execute without simulation
await walletClient.writeContract({ /* ... */ })Use Typed Actions
// ✓ Good: Type-safe
const actions = router.createTypedActions()
.orderSingle({ /* autocomplete works */ })
// ✗ Less ideal: Manual action adding
const actions = router.createActions()
.add(Action.ORDER_SINGLE, params)Add Recommended Actions
// ✓ Good: Automatic settlements
.build({ addRecommendedActions: true, receiver })
// ✗ Manual: Forgetting settlements causes reverts
.build()Check Expected Values
// ✓ Good: Calculate exact value needed
const value = actions.expectedValue({ globalProvision })
await walletClient.writeContract({ value, /* ... */ })
// ✗ Bad: Guessing value
await walletClient.writeContract({ value: parseEther('1'), /* ... */ })Related Documentation
- Router Actions - Available actions and parameters
- Core Classes - Token, Market, and other classes
- Using VifRouter - Contract-level documentation
- Flash Accounting - Protocol mechanics