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 permits (destination address, memo, network, etc.). Creation persists a request but does not submit to a provider.2. Compile
QTG compiles the request into a DAG plan. This involves validating the graph structure, resolving bindings (which exchange credentials or signer metadata to use), and computing a tamper-evident hash of the compiled plan. Applicable on-chain intent addresses are checked at creation.3. Approve (the gate)
The movement begins in PENDING_APPROVAL. Manual approval locks the movement and requires the client to echo its compiled-plan hash. When an existing eligible auto-approve hook succeeds during creation, QTG applies the same approval/reservation path without waiting for a manual action; agent-originated movements still park for human approval.4. Dispatch
Once approved, the dispatcher picks up each ready node in the plan and hands it to the appropriate executor. Before that executor can perform a side effect, dispatch recomputes the compiled-plan hash and repeats the applicable QTG address check, including cooling-period enforcement. For CEX withdrawals, this is the first QTG local destination check; the executor then performs the template literal-pin check and, where available, an exchange saved-address-book pre-read. For an on-chain bridge, the executor builds and signs a transaction through the configured signer path only after its dispatch guards pass. See Movement Authorization Model for the difference between registration, approval, and this revalidation boundary.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 the required terminal states, the movement is marked complete. A definitive failure can mark it failed; an ambiguous side effect can instead require manual intervention while recovery reconciles provider evidence. State transitions are recorded, and configured callback events are delivered through the callback outbox.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 asks QTG to create a movement.
- QTG compiles the plan and places it in
PENDING_APPROVALunless an existing eligible auto-approve hook applies. - If the request has a matching callback configuration, the callback outbox can notify the receiver that approval is needed.
- The Dashboard approval dialog requests a DB-only, digest-bound Approval Brief showing source, destination, asset, amount semantics, guard verdicts, and the compiled-plan hash plus brief/authorization-facts digests; you submit the captured digest (enforced under
MG_AUTHORIZATION_PROJECTION_MODE=enforce, shadow by default). - A manual approval validates the echoed hash and then makes the movement runnable. Dispatch still performs its own hash, allowlist, and executor/provider checks before any transfer is submitted.
What Happens on Failure
Not every transfer succeeds on the first try. QTG handles failures at three levels:
The request state follows the node outcomes: a definitive failure can end in
FAILED, while ambiguous side effects can require MANUAL_INTERVENTION. Relevant transitions use the configured callback outbox; QTG does not treat ambiguity as permission to retry a submission indefinitely.
For the full state machine specification with all 12 node states and transition rules, see States & Transitions.
Callbacks: Keeping External Systems in Sync
For a movement with matching callback configuration and event filters, externally relevant state changes use a callback outbox. 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.