Using off-chain data
This page shows how to enrich your Mimic tasks with off‑chain data. You’ll learn three common patterns:
Pricing convert token balances to USD
Discovery of relevant tokens for a user across a chain and bulk‑transfer them
Custom subgraph queries (e.g., fetch a Uniswap pool price)
We’ll walk through each pattern, the inputs they require, and implementation details you should keep in mind (precision, slippage, and fees).
Pre-reqs: You’ve already read the basic task guide and can
mimic codegen,mimic compile, andmimic deploy.
Use price feeds to act on a USD threshold
Goal: Top up a recipient if their token balance (in USD) falls below a threshold.
import { BigInt, ERC20Token, log, TokenAmount, Transfer, USD } from '@mimicprotocol/lib-ts'
import { ERC20 } from './types/ERC20'
import { inputs } from './types'
export default function main(): void {
const tokenContract = new ERC20(inputs.token, inputs.chainId)
const balance = tokenContract.balanceOf(inputs.recipient)
const token = ERC20Token.fromAddress(inputs.token, inputs.chainId)
const balanceInUsd = TokenAmount.fromBigInt(token, balance).toUsd()
const thresholdUsd = USD.fromStringDecimal(inputs.thresholdUsd)
log.info(`Balance in USD: ${balanceInUsd}`)
if (balanceInUsd.lt(thresholdUsd)) {
const amount = BigInt.fromStringDecimal(inputs.amount, token.decimals)
const maxFee = BigInt.fromStringDecimal(inputs.maxFee, token.decimals)
Transfer.create(token, amount, inputs.recipient, maxFee).send()
}
}
Notes
Convert all human‑readable decimals using
BigInt.fromStringDecimal(value, decimals)to avoid precision loss.maxFeeis specified in token units here; pass a USD‑denominated cap instead by usingTokenAmount.fromStringDecimal(DenominationToken.USD(), ...)(see next example).
Find relevant tokens and send them in one go
Goal: Detect which tokens a user actually holds on a chain and transfer any non‑zero balances to a recipient, paying a single USD‑capped fee.
import { DenominationToken, environment, ListType, log, TokenAmount, TransferBuilder, USD } from '@mimicprotocol/lib-ts'
import { inputs } from './types'
export default function main(): void {
const context = environment.getContext()
const tokens = environment.getRelevantTokens(context.user, [inputs.chainId], USD.zero(), [], ListType.DenyList)
const builder = TransferBuilder.forChain(inputs.chainId)
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i]
builder.addTransferFromTokenAmount(token, inputs.recipient)
log.info(`Adding transfer for ${token} on chain ${inputs.chainId}`)
}
if (builder.transfers.length == 0) {
log.info(`No tokens found on chain ${inputs.chainId}`)
return
}
builder.addMaxFee(TokenAmount.fromStringDecimal(DenominationToken.USD(), inputs.feeAmountUsd)).build().send()
}
Notes
getRelevantTokenshelps you focus on balances that matter. Supply an allow‑list if you want strict control over which tokens are considered.The fee cap is set in USD via
DenominationToken.USD(); the runtime handles conversion.
Query a subgraph for price and swap with slippage
Goal: Fetch a Uniswap pool price from a subgraph, compute expected output, apply slippage in BPS, and submit a swap intent.
import { Address, BigInt, environment, ERC20Token, Swap } from '@mimicprotocol/lib-ts'
import { JSON } from 'json-as/assembly'
import { ERC20 } from './types/ERC20'
import { inputs } from './types'
@json
class UniswapPool {
constructor(
public token0Price: string,
public token1Price: string
) {}
}
@json
class UniswapPoolsData {
constructor(public pools: UniswapPool[]) {}
}
const PRICE_PRECISION: u8 = 40
const BPS_DENOMINATOR = BigInt.fromI32(10_000)
export default function main(): void {
if (inputs.tokenIn == inputs.tokenOut) throw new Error('Token in and out must be different')
if (BigInt.fromI32(inputs.slippageBps as i32) > BPS_DENOMINATOR) throw new Error('Slippage must be between 0 and 100')
const me = environment.getContext().user
const amountIn = new ERC20(inputs.tokenIn, inputs.chainId).balanceOf(me)
if (amountIn.isZero()) throw new Error('No amount in to swap')
const price = getTokenPrice(inputs.chainId, inputs.subgraphId, inputs.tokenIn, inputs.tokenOut)
const tokenIn = ERC20Token.fromAddress(inputs.tokenIn, inputs.chainId)
const tokenOut = ERC20Token.fromAddress(inputs.tokenOut, inputs.chainId)
const expectedOut = amountIn
.times(price)
.upscale(tokenOut.decimals)
.downscale(tokenIn.decimals + PRICE_PRECISION)
const slippageFactor = BPS_DENOMINATOR.minus(BigInt.fromI32(inputs.slippageBps as i32))
const minAmountOut = expectedOut.times(slippageFactor).div(BPS_DENOMINATOR)
Swap.create(inputs.chainId, tokenIn, amountIn, tokenOut, minAmountOut).send()
}
function getTokenPrice(chainId: i32, subgraphId: string, tokenIn: Address, tokenOut: Address): BigInt {
let token0: Address
let token1: Address
if (tokenIn.toString() < tokenOut.toString()) {
token0 = tokenIn
token1 = tokenOut
} else {
token0 = tokenOut
token1 = tokenIn
}
const query = `{pools(where: { token0: "${token0}", token1: "${token1}" }) {token0Price token1Price}}`
const response = environment.subgraphQuery(chainId, subgraphId, query, null)
const data = JSON.parse<UniswapPoolsData>(response.data)
if (tokenIn == token0 && tokenOut === token1) {
return BigInt.fromStringDecimal(data.pools[0].token1Price, PRICE_PRECISION)
} else {
return BigInt.fromStringDecimal(data.pools[0].token0Price, PRICE_PRECISION)
}
}
Why PRICE_PRECISION = 40?
Subgraph prices are strings with decimal precision. We parse them into a big integer using a high fixed precision (40) to minimize rounding error before scaling to token decimals. Match this with your downstream math so
upscale/downscalelands on correct integer units.
Slippage in BPS
slippageBps = 50→ 0.50% buffer. We computeminAmountOut = expectedOut * (1 − bps/10_000).
Edge cases
Ensure the pool exists (
data.pools.length > 0).Consider stable pools whose price may deviate
Handle tokens with non‑standard decimals (e.g., 6, 8).
Next steps
Learn about available APIs for creating intents and interacting with contracts.
Discover advanced CLI commands for testing, validating, and managing tasks.
Build more complex use cases Expand your automation examples.
Last updated