Movement Lifecycle
Every transfer in QTG follows the same lifecycle, whether you are moving 10 USDC between test wallets or routing a six-figure rebalance across three exchanges. Understanding this lifecycle is the single most important concept for operating QTG.What is a Movement?
A Movement is a transfer request that has been compiled into a plan. You start by choosing a template — a reusable blueprint that describes which venue to use, what asset to move, and where it goes. When you create a movement from that template, QTG compiles it into a plan: a directed acyclic graph (DAG) of steps that must execute in order. For example, the template “Move USDC from Upbit to Binance” compiles into three steps: withdraw from Upbit, watch the withdrawal complete, then watch the deposit arrive at Binance. Each step is called a node, and each node runs through a venue-specific executor.The Six Stages
Every movement passes through these stages:1. Create
You submit a transfer request via the API, CLI, or MCP tool. You specify the template, the amount, and any parameters the template requires (destination address, memo, network, etc.).2. Compile
QTG compiles the request into a DAG plan. This involves validating the graph structure, resolving bindings (which exchange credentials to use, which signer to use), and computing a tamper-evident hash of the entire plan. If the template references an address not on the allowlist, compilation fails here — before anything moves.3. Approve (the gate)
The movement enters PENDING_APPROVAL and stops. Nothing executes until an operator (or an auto-approve policy) explicitly approves it. This is the core safety mechanism: even if an agent or automated system creates hundreds of movements, none of them move funds until a human — or a policy the human configured — says yes.4. Dispatch
Once approved, the dispatcher picks up each ready node in the plan and hands it to the appropriate executor. For a CEX withdrawal, the executor calls the exchange API. For an on-chain bridge, the executor builds and signs a transaction via your KMS. Each node goes through a preflight check before execution — including a re-check of the destination address against the allowlist.5. Observe
After dispatch, the observer polls for completion. For CEX transfers this means checking withdrawal and deposit status via the exchange API. For on-chain transfers this means watching for transaction confirmation. The observer handles the inherent uncertainty of external systems: API timeouts, temporary failures, and ambiguous states.6. Complete
When all nodes in the DAG have reached a terminal state, the movement is marked complete (or failed, if a node could not recover). The final state is recorded, audit events are written, and callbacks fire.The Approval Gate in Practice
The approval gate is what makes QTG different from a plain API wrapper. Consider this scenario:- Your trading bot detects an arbitrage opportunity and signals QTG to move 50,000 USDC from Upbit to Binance.
- QTG compiles the plan and places it in PENDING_APPROVAL.
- You get a callback notification on your Slack webhook.
- You review the amount, destination, and route in the dashboard.
- You approve. The transfer executes.
What Happens on Failure
Not every transfer succeeds on the first try. QTG handles failures at three levels:
If a node fails and cannot recover, QTG pauses the movement and fires a callback so you know immediately. It does not silently retry indefinitely or leave funds in limbo.
For the full state machine specification with all 12 node states and transition rules, see States & Transitions.
Callbacks: Keeping External Systems in Sync
Every meaningful state change fires a callback to any URL you registered when creating the movement. Callbacks are:- Durable — stored in an outbox table and retried on delivery failure.
- Signed — HMAC v3 with a nonce, so receivers can verify authenticity and reject replays.
- Non-blocking — callback delivery does not delay the movement itself.